summaryrefslogtreecommitdiffstats
path: root/WebCore/dom
diff options
context:
space:
mode:
authorUpstream <upstream-import@none>1970-01-12 13:46:40 +0000
committerUpstream <upstream-import@none>1970-01-12 13:46:40 +0000
commitd8543bb6618c17b12da906afa77d216f58cf4058 (patch)
treec58dc05ed86825bd0ef8d305d58c8205106b540f /WebCore/dom
downloadexternal_webkit-d8543bb6618c17b12da906afa77d216f58cf4058.zip
external_webkit-d8543bb6618c17b12da906afa77d216f58cf4058.tar.gz
external_webkit-d8543bb6618c17b12da906afa77d216f58cf4058.tar.bz2
external/webkit r30707
Diffstat (limited to 'WebCore/dom')
-rw-r--r--WebCore/dom/Attr.cpp195
-rw-r--r--WebCore/dom/Attr.h99
-rw-r--r--WebCore/dom/Attr.idl46
-rw-r--r--WebCore/dom/Attribute.cpp47
-rw-r--r--WebCore/dom/Attribute.h89
-rw-r--r--WebCore/dom/BeforeTextInsertedEvent.cpp40
-rw-r--r--WebCore/dom/BeforeTextInsertedEvent.h48
-rw-r--r--WebCore/dom/BeforeUnloadEvent.cpp49
-rw-r--r--WebCore/dom/BeforeUnloadEvent.h48
-rw-r--r--WebCore/dom/CDATASection.cpp70
-rw-r--r--WebCore/dom/CDATASection.h49
-rw-r--r--WebCore/dom/CDATASection.idl29
-rw-r--r--WebCore/dom/CSSMappedAttributeDeclaration.cpp38
-rw-r--r--WebCore/dom/CSSMappedAttributeDeclaration.h60
-rw-r--r--WebCore/dom/CharacterData.cpp261
-rw-r--r--WebCore/dom/CharacterData.h73
-rw-r--r--WebCore/dom/CharacterData.idl55
-rw-r--r--WebCore/dom/ChildNodeList.cpp112
-rw-r--r--WebCore/dom/ChildNodeList.h46
-rw-r--r--WebCore/dom/ClassNames.cpp56
-rw-r--r--WebCore/dom/ClassNames.h68
-rw-r--r--WebCore/dom/ClassNodeList.cpp65
-rw-r--r--WebCore/dom/ClassNodeList.h52
-rwxr-xr-xWebCore/dom/Clipboard.cpp139
-rw-r--r--WebCore/dom/Clipboard.h112
-rw-r--r--WebCore/dom/ClipboardAccessPolicy.h37
-rw-r--r--WebCore/dom/ClipboardEvent.cpp44
-rw-r--r--WebCore/dom/ClipboardEvent.h49
-rw-r--r--WebCore/dom/Comment.cpp72
-rw-r--r--WebCore/dom/Comment.h53
-rw-r--r--WebCore/dom/Comment.idl29
-rw-r--r--WebCore/dom/ContainerNode.cpp1001
-rw-r--r--WebCore/dom/ContainerNode.h95
-rw-r--r--WebCore/dom/DOMCoreException.h46
-rw-r--r--WebCore/dom/DOMCoreException.idl71
-rw-r--r--WebCore/dom/DOMImplementation.cpp396
-rw-r--r--WebCore/dom/DOMImplementation.h76
-rw-r--r--WebCore/dom/DOMImplementation.idl58
-rw-r--r--WebCore/dom/DocPtr.h115
-rw-r--r--WebCore/dom/Document.cpp3830
-rw-r--r--WebCore/dom/Document.h960
-rw-r--r--WebCore/dom/Document.idl236
-rw-r--r--WebCore/dom/DocumentFragment.cpp77
-rw-r--r--WebCore/dom/DocumentFragment.h47
-rw-r--r--WebCore/dom/DocumentFragment.idl29
-rw-r--r--WebCore/dom/DocumentMarker.h60
-rw-r--r--WebCore/dom/DocumentType.cpp128
-rw-r--r--WebCore/dom/DocumentType.h77
-rw-r--r--WebCore/dom/DocumentType.idl43
-rw-r--r--WebCore/dom/DynamicNodeList.cpp183
-rw-r--r--WebCore/dom/DynamicNodeList.h80
-rw-r--r--WebCore/dom/EditingText.cpp52
-rw-r--r--WebCore/dom/EditingText.h44
-rw-r--r--WebCore/dom/Element.cpp1230
-rw-r--r--WebCore/dom/Element.h227
-rw-r--r--WebCore/dom/Element.idl121
-rw-r--r--WebCore/dom/Entity.cpp110
-rw-r--r--WebCore/dom/Entity.h58
-rw-r--r--WebCore/dom/Entity.idl32
-rw-r--r--WebCore/dom/EntityReference.cpp84
-rw-r--r--WebCore/dom/EntityReference.h49
-rw-r--r--WebCore/dom/EntityReference.idl29
-rw-r--r--WebCore/dom/Event.cpp174
-rw-r--r--WebCore/dom/Event.h159
-rw-r--r--WebCore/dom/Event.idl82
-rw-r--r--WebCore/dom/EventException.h53
-rw-r--r--WebCore/dom/EventException.idl50
-rw-r--r--WebCore/dom/EventListener.h40
-rw-r--r--WebCore/dom/EventListener.idl32
-rw-r--r--WebCore/dom/EventNames.cpp51
-rw-r--r--WebCore/dom/EventNames.h125
-rw-r--r--WebCore/dom/EventTarget.cpp335
-rw-r--r--WebCore/dom/EventTarget.h116
-rw-r--r--WebCore/dom/EventTarget.idl39
-rw-r--r--WebCore/dom/EventTargetNode.cpp418
-rw-r--r--WebCore/dom/EventTargetNode.h114
-rw-r--r--WebCore/dom/ExceptionBase.cpp50
-rw-r--r--WebCore/dom/ExceptionBase.h56
-rw-r--r--WebCore/dom/ExceptionCode.cpp160
-rw-r--r--WebCore/dom/ExceptionCode.h78
-rw-r--r--WebCore/dom/KeyboardEvent.cpp166
-rw-r--r--WebCore/dom/KeyboardEvent.h100
-rw-r--r--WebCore/dom/KeyboardEvent.idl80
-rw-r--r--WebCore/dom/MappedAttribute.cpp35
-rw-r--r--WebCore/dom/MappedAttribute.h67
-rw-r--r--WebCore/dom/MappedAttributeEntry.h55
-rw-r--r--WebCore/dom/MessageEvent.cpp77
-rw-r--r--WebCore/dom/MessageEvent.h65
-rw-r--r--WebCore/dom/MessageEvent.idl40
-rw-r--r--WebCore/dom/MouseEvent.cpp122
-rw-r--r--WebCore/dom/MouseEvent.h76
-rw-r--r--WebCore/dom/MouseEvent.idl66
-rw-r--r--WebCore/dom/MouseRelatedEvent.cpp189
-rw-r--r--WebCore/dom/MouseRelatedEvent.h78
-rw-r--r--WebCore/dom/MutationEvent.cpp68
-rw-r--r--WebCore/dom/MutationEvent.h69
-rw-r--r--WebCore/dom/MutationEvent.idl49
-rw-r--r--WebCore/dom/NameNodeList.cpp51
-rw-r--r--WebCore/dom/NameNodeList.h49
-rw-r--r--WebCore/dom/NamedAttrMap.cpp360
-rw-r--r--WebCore/dom/NamedAttrMap.h103
-rw-r--r--WebCore/dom/NamedMappedAttrMap.cpp91
-rw-r--r--WebCore/dom/NamedMappedAttrMap.h71
-rw-r--r--WebCore/dom/NamedNodeMap.h68
-rw-r--r--WebCore/dom/NamedNodeMap.idl60
-rw-r--r--WebCore/dom/Node.cpp1656
-rw-r--r--WebCore/dom/Node.h514
-rw-r--r--WebCore/dom/Node.idl132
-rw-r--r--WebCore/dom/NodeFilter.cpp38
-rw-r--r--WebCore/dom/NodeFilter.h81
-rw-r--r--WebCore/dom/NodeFilter.idl50
-rw-r--r--WebCore/dom/NodeFilterCondition.cpp39
-rw-r--r--WebCore/dom/NodeFilterCondition.h48
-rw-r--r--WebCore/dom/NodeIterator.cpp227
-rw-r--r--WebCore/dom/NodeIterator.h74
-rw-r--r--WebCore/dom/NodeIterator.idl39
-rw-r--r--WebCore/dom/NodeList.h47
-rw-r--r--WebCore/dom/NodeList.idl38
-rw-r--r--WebCore/dom/Notation.cpp61
-rw-r--r--WebCore/dom/Notation.h55
-rw-r--r--WebCore/dom/Notation.idl31
-rw-r--r--WebCore/dom/OverflowEvent.cpp73
-rw-r--r--WebCore/dom/OverflowEvent.h60
-rw-r--r--WebCore/dom/OverflowEvent.idl43
-rw-r--r--WebCore/dom/Position.cpp763
-rw-r--r--WebCore/dom/Position.h125
-rw-r--r--WebCore/dom/PositionIterator.cpp155
-rw-r--r--WebCore/dom/PositionIterator.h73
-rw-r--r--WebCore/dom/ProcessingInstruction.cpp255
-rw-r--r--WebCore/dom/ProcessingInstruction.h89
-rw-r--r--WebCore/dom/ProcessingInstruction.idl42
-rw-r--r--WebCore/dom/ProgressEvent.cpp63
-rw-r--r--WebCore/dom/ProgressEvent.h59
-rw-r--r--WebCore/dom/ProgressEvent.idl42
-rw-r--r--WebCore/dom/QualifiedName.cpp181
-rw-r--r--WebCore/dom/QualifiedName.h97
-rw-r--r--WebCore/dom/Range.cpp1718
-rw-r--r--WebCore/dom/Range.h145
-rw-r--r--WebCore/dom/Range.idl120
-rw-r--r--WebCore/dom/RangeException.h52
-rw-r--r--WebCore/dom/RangeException.idl40
-rw-r--r--WebCore/dom/RegisteredEventListener.cpp46
-rw-r--r--WebCore/dom/RegisteredEventListener.h60
-rw-r--r--WebCore/dom/SelectorNodeList.cpp57
-rw-r--r--WebCore/dom/SelectorNodeList.h47
-rw-r--r--WebCore/dom/StaticNodeList.cpp62
-rw-r--r--WebCore/dom/StaticNodeList.h56
-rw-r--r--WebCore/dom/StyleElement.cpp98
-rw-r--r--WebCore/dom/StyleElement.h56
-rw-r--r--WebCore/dom/StyledElement.cpp486
-rw-r--r--WebCore/dom/StyledElement.h85
-rw-r--r--WebCore/dom/TagNodeList.cpp51
-rw-r--r--WebCore/dom/TagNodeList.h46
-rw-r--r--WebCore/dom/Text.cpp330
-rw-r--r--WebCore/dom/Text.h75
-rw-r--r--WebCore/dom/Text.idl39
-rw-r--r--WebCore/dom/TextEvent.cpp69
-rw-r--r--WebCore/dom/TextEvent.h62
-rw-r--r--WebCore/dom/TextEvent.idl43
-rw-r--r--WebCore/dom/Tokenizer.h78
-rw-r--r--WebCore/dom/Traversal.cpp61
-rw-r--r--WebCore/dom/Traversal.h63
-rw-r--r--WebCore/dom/TreeWalker.cpp285
-rw-r--r--WebCore/dom/TreeWalker.h66
-rw-r--r--WebCore/dom/TreeWalker.idl41
-rw-r--r--WebCore/dom/UIEvent.cpp99
-rw-r--r--WebCore/dom/UIEvent.h68
-rw-r--r--WebCore/dom/UIEvent.idl45
-rw-r--r--WebCore/dom/UIEventWithKeyState.cpp34
-rw-r--r--WebCore/dom/UIEventWithKeyState.h70
-rw-r--r--WebCore/dom/WheelEvent.cpp85
-rw-r--r--WebCore/dom/WheelEvent.h61
-rw-r--r--WebCore/dom/WheelEvent.idl64
-rw-r--r--WebCore/dom/XMLTokenizer.cpp2105
-rw-r--r--WebCore/dom/XMLTokenizer.h180
-rwxr-xr-xWebCore/dom/make_names.pl497
176 files changed, 29256 insertions, 0 deletions
diff --git a/WebCore/dom/Attr.cpp b/WebCore/dom/Attr.cpp
new file mode 100644
index 0000000..52a2581
--- /dev/null
+++ b/WebCore/dom/Attr.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Peter Kelly (pmk@post.com)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include "config.h"
+#include "Attr.h"
+
+#include "Document.h"
+#include "Element.h"
+#include "ExceptionCode.h"
+#include "Text.h"
+
+namespace WebCore {
+
+Attr::Attr(Element* element, Document* docPtr, PassRefPtr<Attribute> a)
+ : ContainerNode(docPtr),
+ m_element(element),
+ m_attribute(a),
+ m_ignoreChildrenChanged(0)
+{
+ ASSERT(!m_attribute->attr());
+ m_attribute->m_impl = this;
+ m_attrWasSpecifiedOrElementHasRareData = true;
+}
+
+Attr::~Attr()
+{
+ ASSERT(m_attribute->attr() == this);
+ m_attribute->m_impl = 0;
+}
+
+void Attr::createTextChild()
+{
+ ASSERT(refCount());
+ if (!m_attribute->value().isEmpty()) {
+ RefPtr<Text> textNode = document()->createTextNode(m_attribute->value().string());
+
+ // This does everything appendChild() would do in this situation (assuming m_ignoreChildrenChanged was set),
+ // but much more efficiently.
+ textNode->setParent(this);
+ setFirstChild(textNode.get());
+ setLastChild(textNode.get());
+ }
+}
+
+String Attr::nodeName() const
+{
+ return name();
+}
+
+Node::NodeType Attr::nodeType() const
+{
+ return ATTRIBUTE_NODE;
+}
+
+const AtomicString& Attr::localName() const
+{
+ return m_attribute->localName();
+}
+
+const AtomicString& Attr::namespaceURI() const
+{
+ return m_attribute->namespaceURI();
+}
+
+const AtomicString& Attr::prefix() const
+{
+ return m_attribute->prefix();
+}
+
+void Attr::setPrefix(const AtomicString &_prefix, ExceptionCode& ec)
+{
+ ec = 0;
+ checkSetPrefix(_prefix, ec);
+ if (ec)
+ return;
+
+ m_attribute->setPrefix(_prefix);
+}
+
+String Attr::nodeValue() const
+{
+ return value();
+}
+
+void Attr::setValue( const String& v, ExceptionCode& ec)
+{
+ ec = 0;
+
+ // do not interprete entities in the string, its literal!
+
+ // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly
+ if (isReadOnlyNode()) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return;
+ }
+
+ int e = 0;
+ m_ignoreChildrenChanged++;
+ removeChildren();
+ appendChild(document()->createTextNode(v), e);
+ m_ignoreChildrenChanged--;
+
+ m_attribute->setValue(v.impl());
+ if (m_element)
+ m_element->attributeChanged(m_attribute.get());
+}
+
+void Attr::setNodeValue(const String& v, ExceptionCode& ec)
+{
+ // NO_MODIFICATION_ALLOWED_ERR: taken care of by setValue()
+ setValue(v, ec);
+}
+
+PassRefPtr<Node> Attr::cloneNode(bool /*deep*/)
+{
+ RefPtr<Attr> clone = new Attr(0, document(), m_attribute->clone());
+ cloneChildNodes(clone.get());
+ return clone.release();
+}
+
+// DOM Section 1.1.1
+bool Attr::childTypeAllowed(NodeType type)
+{
+ switch (type) {
+ case TEXT_NODE:
+ case ENTITY_REFERENCE_NODE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void Attr::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
+{
+ if (m_ignoreChildrenChanged > 0)
+ return;
+
+ Node::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
+
+ // FIXME: We should include entity references in the value
+
+ String val = "";
+ for (Node *n = firstChild(); n; n = n->nextSibling()) {
+ if (n->isTextNode())
+ val += static_cast<Text *>(n)->data();
+ }
+
+ m_attribute->setValue(val.impl());
+ if (m_element)
+ m_element->attributeChanged(m_attribute.get());
+}
+
+String Attr::toString() const
+{
+ String result;
+
+ result += nodeName();
+
+ // FIXME: substitute entities for any instances of " or ' --
+ // maybe easier to just use text value and ignore existing
+ // entity refs?
+
+ if (firstChild() != NULL) {
+ result += "=\"";
+
+ for (Node *child = firstChild(); child != NULL; child = child->nextSibling()) {
+ result += child->toString();
+ }
+
+ result += "\"";
+ }
+
+ return result;
+}
+
+}
diff --git a/WebCore/dom/Attr.h b/WebCore/dom/Attr.h
new file mode 100644
index 0000000..d71a79e
--- /dev/null
+++ b/WebCore/dom/Attr.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Peter Kelly (pmk@post.com)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Attr_h
+#define Attr_h
+
+#include "ContainerNode.h"
+#include "Attribute.h"
+
+namespace WebCore {
+
+// this has no counterpart in DOM, purely internal
+// representation of the nodevalue of an Attr.
+// the actual Attr (Attr) with its value as textchild
+// is only allocated on demand by the DOM bindings.
+// Any use of Attr inside khtml should be avoided.
+
+// Attr can have Text and EntityReference children
+// therefore it has to be a fullblown Node. The plan
+// is to dynamically allocate a textchild and store the
+// resulting nodevalue in the Attribute upon
+// destruction. however, this is not yet implemented.
+
+class Attr : public ContainerNode {
+ friend class NamedAttrMap;
+
+public:
+ Attr(Element*, Document*, PassRefPtr<Attribute>);
+ ~Attr();
+
+ // Call this after calling the constructor so the
+ // Attr node isn't floating when we append the text node.
+ void createTextChild();
+
+ // DOM methods & attributes for Attr
+ String name() const { return qualifiedName().toString(); }
+ bool specified() const { return m_attrWasSpecifiedOrElementHasRareData; }
+ Element* ownerElement() const { return m_element; }
+
+ String value() const { return m_attribute->value(); }
+ void setValue(const String&, ExceptionCode&);
+
+ // DOM methods overridden from parent classes
+ virtual String nodeName() const;
+ virtual NodeType nodeType() const;
+ virtual const AtomicString& localName() const;
+ virtual const AtomicString& namespaceURI() const;
+ virtual const AtomicString& prefix() const;
+ virtual void setPrefix(const AtomicString&, ExceptionCode&);
+
+ virtual String nodeValue() const;
+ virtual void setNodeValue(const String&, ExceptionCode&);
+ virtual PassRefPtr<Node> cloneNode(bool deep);
+
+ // Other methods (not part of DOM)
+ virtual bool isAttributeNode() const { return true; }
+ virtual bool childTypeAllowed(NodeType);
+
+ virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
+ virtual String toString() const;
+
+ Attribute* attr() const { return m_attribute.get(); }
+ const QualifiedName& qualifiedName() const { return m_attribute->name(); }
+
+ // An extension to get presentational information for attributes.
+ CSSStyleDeclaration* style() { return m_attribute->style(); }
+
+ void setSpecified(bool specified) { m_attrWasSpecifiedOrElementHasRareData = specified; }
+
+private:
+ Element* m_element;
+ RefPtr<Attribute> m_attribute;
+ int m_ignoreChildrenChanged;
+};
+
+} //namespace
+
+#endif
diff --git a/WebCore/dom/Attr.idl b/WebCore/dom/Attr.idl
new file mode 100644
index 0000000..eeb064b
--- /dev/null
+++ b/WebCore/dom/Attr.idl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module core {
+
+ interface [
+ GenerateConstructor,
+ InterfaceUUID=EEE8E22B-22C3-4e50-95F4-5E0B8AAD8231,
+ ImplementationUUID=41B16348-D8E7-4d21-BFDB-125705B7E91F
+ ] Attr : EventTargetNode {
+
+ // DOM Level 1
+
+ readonly attribute [ConvertNullStringTo=Null] DOMString name;
+ readonly attribute boolean specified;
+ attribute [ConvertNullStringTo=Null, ConvertNullToNullString, CustomSetter] DOMString value
+ setter raises(DOMException);
+
+ // DOM Level 2
+
+ readonly attribute Element ownerElement;
+
+ // extensions
+#if !defined(LANGUAGE_COM)
+ readonly attribute CSSStyleDeclaration style;
+#endif
+ };
+
+}
diff --git a/WebCore/dom/Attribute.cpp b/WebCore/dom/Attribute.cpp
new file mode 100644
index 0000000..351b55a
--- /dev/null
+++ b/WebCore/dom/Attribute.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Peter Kelly (pmk@post.com)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "Attribute.h"
+
+#include "Attr.h"
+#include "Element.h"
+
+namespace WebCore {
+
+Attribute* Attribute::clone(bool) const
+{
+ return new Attribute(m_name, m_value);
+}
+
+PassRefPtr<Attr> Attribute::createAttrIfNeeded(Element* e)
+{
+ RefPtr<Attr> r = m_impl;
+ if (!r) {
+ r = new Attr(e, e->document(), this);
+ r->createTextChild();
+ }
+ return r.release();
+}
+
+}
diff --git a/WebCore/dom/Attribute.h b/WebCore/dom/Attribute.h
new file mode 100644
index 0000000..d515ea7
--- /dev/null
+++ b/WebCore/dom/Attribute.h
@@ -0,0 +1,89 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Peter Kelly (pmk@post.com)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Attribute_h
+#define Attribute_h
+
+#include "QualifiedName.h"
+
+namespace WebCore {
+
+class Attr;
+class CSSStyleDeclaration;
+class Element;
+class NamedAttrMap;
+
+// this has no counterpart in DOM, purely internal
+// representation of the nodevalue of an Attr.
+// the actual Attr (Attr) with its value as textchild
+// is only allocated on demand by the DOM bindings.
+// Any use of Attr inside khtml should be avoided.
+class Attribute : public RefCounted<Attribute> {
+ friend class Attr;
+ friend class Element;
+ friend class NamedAttrMap;
+public:
+ // null value is forbidden !
+ Attribute(const QualifiedName& name, const AtomicString& value)
+ : RefCounted<Attribute>(0), m_name(name), m_value(value), m_impl(0)
+ {}
+
+ Attribute(const AtomicString& name, const AtomicString& value)
+ : RefCounted<Attribute>(0), m_name(nullAtom, name, nullAtom), m_value(value), m_impl(0)
+ {}
+
+ virtual ~Attribute() { }
+
+ const AtomicString& value() const { return m_value; }
+ const AtomicString& prefix() const { return m_name.prefix(); }
+ const AtomicString& localName() const { return m_name.localName(); }
+ const AtomicString& namespaceURI() const { return m_name.namespaceURI(); }
+
+ const QualifiedName& name() const { return m_name; }
+
+ Attr* attr() const { return m_impl; }
+ PassRefPtr<Attr> createAttrIfNeeded(Element*);
+
+ bool isNull() const { return m_value.isNull(); }
+ bool isEmpty() const { return m_value.isEmpty(); }
+
+ virtual Attribute* clone(bool preserveDecl = true) const;
+
+ // An extension to get the style information for presentational attributes.
+ virtual CSSStyleDeclaration* style() const { return 0; }
+
+ void setValue(const AtomicString& value) { m_value = value; }
+ void setPrefix(const AtomicString& prefix) { m_name.setPrefix(prefix); }
+
+private:
+ QualifiedName m_name;
+ AtomicString m_value;
+ Attr* m_impl;
+};
+
+} //namespace
+
+#endif
diff --git a/WebCore/dom/BeforeTextInsertedEvent.cpp b/WebCore/dom/BeforeTextInsertedEvent.cpp
new file mode 100644
index 0000000..be27adc
--- /dev/null
+++ b/WebCore/dom/BeforeTextInsertedEvent.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2005 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "BeforeTextInsertedEvent.h"
+
+#include "EventNames.h"
+
+namespace WebCore {
+
+using namespace EventNames;
+
+BeforeTextInsertedEvent::BeforeTextInsertedEvent(const String& text)
+ : Event(webkitBeforeTextInsertedEvent, false, true), m_text(text)
+{
+}
+
+}
diff --git a/WebCore/dom/BeforeTextInsertedEvent.h b/WebCore/dom/BeforeTextInsertedEvent.h
new file mode 100644
index 0000000..dacfd71
--- /dev/null
+++ b/WebCore/dom/BeforeTextInsertedEvent.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 BeforeTextInsertedEvent_h
+#define BeforeTextInsertedEvent_h
+
+#include "Event.h"
+
+namespace WebCore {
+
+class BeforeTextInsertedEvent : public Event {
+public:
+ BeforeTextInsertedEvent(const String&);
+
+ virtual bool isBeforeTextInsertedEvent() const { return true; }
+
+ const String& text() const { return m_text; }
+ void setText(const String& s) { m_text = s; }
+
+private:
+ String m_text;
+};
+
+} // namespace
+
+#endif
diff --git a/WebCore/dom/BeforeUnloadEvent.cpp b/WebCore/dom/BeforeUnloadEvent.cpp
new file mode 100644
index 0000000..b1cafe1
--- /dev/null
+++ b/WebCore/dom/BeforeUnloadEvent.cpp
@@ -0,0 +1,49 @@
+/**
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2003, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "BeforeUnloadEvent.h"
+
+#include "EventNames.h"
+
+namespace WebCore {
+
+using namespace EventNames;
+
+BeforeUnloadEvent::BeforeUnloadEvent()
+ : Event(beforeunloadEvent, false, true)
+{
+}
+
+bool BeforeUnloadEvent::storesResultAsString() const
+{
+ return true;
+}
+
+void BeforeUnloadEvent::storeResult(const String& s)
+{
+ m_result = s;
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/BeforeUnloadEvent.h b/WebCore/dom/BeforeUnloadEvent.h
new file mode 100644
index 0000000..6eecb73
--- /dev/null
+++ b/WebCore/dom/BeforeUnloadEvent.h
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef BeforeUnloadEvent_h
+#define BeforeUnloadEvent_h
+
+#include "Event.h"
+
+namespace WebCore {
+
+ class BeforeUnloadEvent : public Event {
+ public:
+ BeforeUnloadEvent();
+
+ virtual bool storesResultAsString() const;
+ virtual void storeResult(const String&);
+
+ String result() const { return m_result; }
+
+ private:
+ String m_result;
+ };
+
+} // namespace WebCore
+
+#endif // BeforeUnloadEvent_h
diff --git a/WebCore/dom/CDATASection.cpp b/WebCore/dom/CDATASection.cpp
new file mode 100644
index 0000000..3f3d472
--- /dev/null
+++ b/WebCore/dom/CDATASection.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "CDATASection.h"
+
+#include "Document.h"
+
+namespace WebCore {
+
+CDATASection::CDATASection(Document* document, const String& text)
+ : Text(document, text)
+{
+}
+
+CDATASection::~CDATASection()
+{
+}
+
+String CDATASection::nodeName() const
+{
+ return "#cdata-section";
+}
+
+Node::NodeType CDATASection::nodeType() const
+{
+ return CDATA_SECTION_NODE;
+}
+
+PassRefPtr<Node> CDATASection::cloneNode(bool /*deep*/)
+{
+ return new CDATASection(document(), m_data);
+}
+
+// DOM Section 1.1.1
+bool CDATASection::childTypeAllowed(NodeType)
+{
+ return false;
+}
+
+PassRefPtr<Text> CDATASection::createNew(PassRefPtr<StringImpl> string)
+{
+ return new CDATASection(document(), string);
+}
+
+String CDATASection::toString() const
+{
+ // FIXME: We need to substitute entity references.
+ return "<![CDATA[" + data() + "]]>";
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/CDATASection.h b/WebCore/dom/CDATASection.h
new file mode 100644
index 0000000..7a21a36
--- /dev/null
+++ b/WebCore/dom/CDATASection.h
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef CDATASection_h
+#define CDATASection_h
+
+#include "Text.h"
+
+namespace WebCore {
+
+class CDATASection : public Text {
+public:
+ CDATASection(Document*, const String&);
+ virtual ~CDATASection();
+
+ virtual String nodeName() const;
+ virtual NodeType nodeType() const;
+ virtual PassRefPtr<Node> cloneNode(bool deep);
+ virtual bool childTypeAllowed(NodeType);
+ virtual String toString() const;
+
+protected:
+ virtual PassRefPtr<Text> createNew(PassRefPtr<StringImpl>);
+};
+
+} // namespace WebCore
+
+#endif // CDATASection_h
diff --git a/WebCore/dom/CDATASection.idl b/WebCore/dom/CDATASection.idl
new file mode 100644
index 0000000..7c6c1e6
--- /dev/null
+++ b/WebCore/dom/CDATASection.idl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module core {
+
+ interface [
+ GenerateConstructor,
+ InterfaceUUID=DC8E30FD-42DD-4a12-9B74-78D634321B41,
+ ImplementationUUID=10A5D70C-D93E-409c-A6BA-9D7CB4E3D06A
+ ] CDATASection : Text {
+ };
+
+}
diff --git a/WebCore/dom/CSSMappedAttributeDeclaration.cpp b/WebCore/dom/CSSMappedAttributeDeclaration.cpp
new file mode 100644
index 0000000..7fe0915
--- /dev/null
+++ b/WebCore/dom/CSSMappedAttributeDeclaration.cpp
@@ -0,0 +1,38 @@
+/**
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Peter Kelly (pmk@post.com)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include "config.h"
+#include "CSSMappedAttributeDeclaration.h"
+
+#include "StyledElement.h"
+
+namespace WebCore {
+
+CSSMappedAttributeDeclaration::~CSSMappedAttributeDeclaration()
+{
+ if (m_entryType != ePersistent)
+ StyledElement::removeMappedAttributeDecl(m_entryType, m_attrName, m_attrValue);
+}
+
+}
diff --git a/WebCore/dom/CSSMappedAttributeDeclaration.h b/WebCore/dom/CSSMappedAttributeDeclaration.h
new file mode 100644
index 0000000..cacb7de
--- /dev/null
+++ b/WebCore/dom/CSSMappedAttributeDeclaration.h
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Peter Kelly (pmk@post.com)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef CSSMappedAttributeDeclaration_h
+#define CSSMappedAttributeDeclaration_h
+
+#include "CSSMutableStyleDeclaration.h"
+#include "MappedAttributeEntry.h"
+#include "QualifiedName.h"
+
+namespace WebCore {
+
+class CSSMappedAttributeDeclaration : public CSSMutableStyleDeclaration {
+public:
+ CSSMappedAttributeDeclaration(CSSRule* parentRule)
+ : CSSMutableStyleDeclaration(parentRule)
+ , m_entryType(eNone)
+ , m_attrName(anyQName()) { }
+
+ virtual ~CSSMappedAttributeDeclaration();
+
+ void setMappedState(MappedAttributeEntry type, const QualifiedName& name, const AtomicString& val)
+ {
+ m_entryType = type;
+ m_attrName = name;
+ m_attrValue = val;
+ }
+
+private:
+ MappedAttributeEntry m_entryType;
+ QualifiedName m_attrName;
+ AtomicString m_attrValue;
+};
+
+} //namespace
+
+#endif
diff --git a/WebCore/dom/CharacterData.cpp b/WebCore/dom/CharacterData.cpp
new file mode 100644
index 0000000..1228c98
--- /dev/null
+++ b/WebCore/dom/CharacterData.cpp
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "CharacterData.h"
+
+#include "CString.h"
+#include "Document.h"
+#include "EventNames.h"
+#include "ExceptionCode.h"
+#include "MutationEvent.h"
+#include "RenderText.h"
+
+namespace WebCore {
+
+using namespace EventNames;
+
+CharacterData::CharacterData(Document *doc)
+ : EventTargetNode(doc)
+{
+}
+
+CharacterData::CharacterData(Document *doc, const String &_text)
+ : EventTargetNode(doc)
+{
+ m_data = _text.impl() ? _text.impl() : StringImpl::empty();
+}
+
+CharacterData::~CharacterData()
+{
+}
+
+void CharacterData::setData(const String& data, ExceptionCode& ec)
+{
+ // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly
+ if (isReadOnlyNode()) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return;
+ }
+
+ if (equal(m_data.get(), data.impl()))
+ return;
+
+ RefPtr<StringImpl> oldStr = m_data;
+ m_data = data.impl();
+
+ if ((!renderer() || !rendererIsNeeded(renderer()->style())) && attached()) {
+ detach();
+ attach();
+ } else if (renderer())
+ static_cast<RenderText*>(renderer())->setText(m_data);
+
+ dispatchModifiedEvent(oldStr.get());
+
+ document()->removeMarkers(this);
+}
+
+String CharacterData::substringData( const unsigned offset, const unsigned count, ExceptionCode& ec)
+{
+ ec = 0;
+ checkCharDataOperation(offset, ec);
+ if (ec)
+ return String();
+
+ return m_data->substring(offset, count);
+}
+
+void CharacterData::appendData( const String &arg, ExceptionCode& ec)
+{
+ ec = 0;
+
+ // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly
+ if (isReadOnlyNode()) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return;
+ }
+
+ String newStr = m_data;
+ newStr.append(arg);
+
+ RefPtr<StringImpl> oldStr = m_data;
+ m_data = newStr.impl();
+
+ if ((!renderer() || !rendererIsNeeded(renderer()->style())) && attached()) {
+ detach();
+ attach();
+ } else if (renderer())
+ static_cast<RenderText*>(renderer())->setTextWithOffset(m_data, oldStr->length(), 0);
+
+ dispatchModifiedEvent(oldStr.get());
+}
+
+void CharacterData::insertData( const unsigned offset, const String &arg, ExceptionCode& ec)
+{
+ ec = 0;
+ checkCharDataOperation(offset, ec);
+ if (ec)
+ return;
+
+ String newStr = m_data;
+ newStr.insert(arg, offset);
+
+ RefPtr<StringImpl> oldStr = m_data;
+ m_data = newStr.impl();
+
+ if ((!renderer() || !rendererIsNeeded(renderer()->style())) && attached()) {
+ detach();
+ attach();
+ } else if (renderer())
+ static_cast<RenderText*>(renderer())->setTextWithOffset(m_data, offset, 0);
+
+ dispatchModifiedEvent(oldStr.get());
+
+ // update the markers for spell checking and grammar checking
+ unsigned length = arg.length();
+ document()->shiftMarkers(this, offset, length);
+}
+
+void CharacterData::deleteData( const unsigned offset, const unsigned count, ExceptionCode& ec)
+{
+ ec = 0;
+ checkCharDataOperation(offset, ec);
+ if (ec)
+ return;
+
+ String newStr = m_data;
+ newStr.remove(offset, count);
+
+ RefPtr<StringImpl> oldStr = m_data;
+ m_data = newStr.impl();
+
+ if ((!renderer() || !rendererIsNeeded(renderer()->style())) && attached()) {
+ detach();
+ attach();
+ } else if (renderer())
+ static_cast<RenderText*>(renderer())->setTextWithOffset(m_data, offset, count);
+
+ dispatchModifiedEvent(oldStr.get());
+
+ // update the markers for spell checking and grammar checking
+ document()->removeMarkers(this, offset, count);
+ document()->shiftMarkers(this, offset + count, -static_cast<int>(count));
+}
+
+void CharacterData::replaceData( const unsigned offset, const unsigned count, const String &arg, ExceptionCode& ec)
+{
+ ec = 0;
+ checkCharDataOperation(offset, ec);
+ if (ec)
+ return;
+
+ unsigned realCount;
+ if (offset + count > m_data->length())
+ realCount = m_data->length()-offset;
+ else
+ realCount = count;
+
+ String newStr = m_data;
+ newStr.remove(offset, realCount);
+ newStr.insert(arg, offset);
+
+ RefPtr<StringImpl> oldStr = m_data;
+ m_data = newStr.impl();
+
+ if ((!renderer() || !rendererIsNeeded(renderer()->style())) && attached()) {
+ detach();
+ attach();
+ } else if (renderer())
+ static_cast<RenderText*>(renderer())->setTextWithOffset(m_data, offset, count);
+
+ dispatchModifiedEvent(oldStr.get());
+
+ // update the markers for spell checking and grammar checking
+ int diff = arg.length() - count;
+ document()->removeMarkers(this, offset, count);
+ document()->shiftMarkers(this, offset + count, diff);
+}
+
+String CharacterData::nodeValue() const
+{
+ return m_data;
+}
+
+bool CharacterData::containsOnlyWhitespace() const
+{
+ if (m_data)
+ return m_data->containsOnlyWhitespace();
+ return true;
+}
+
+void CharacterData::setNodeValue( const String &_nodeValue, ExceptionCode& ec)
+{
+ // NO_MODIFICATION_ALLOWED_ERR: taken care of by setData()
+ setData(_nodeValue, ec);
+}
+
+void CharacterData::dispatchModifiedEvent(StringImpl *prevValue)
+{
+ if (parentNode())
+ parentNode()->childrenChanged();
+ if (document()->hasListenerType(Document::DOMCHARACTERDATAMODIFIED_LISTENER)) {
+ ExceptionCode ec;
+ dispatchEvent(new MutationEvent(DOMCharacterDataModifiedEvent, true, false, 0, prevValue, m_data, String(), 0), ec);
+ }
+ dispatchSubtreeModifiedEvent();
+}
+
+void CharacterData::checkCharDataOperation( const unsigned offset, ExceptionCode& ec)
+{
+ ec = 0;
+
+ // INDEX_SIZE_ERR: Raised if the specified offset is negative or greater than the number of 16-bit
+ // units in data.
+ if (offset > m_data->length()) {
+ ec = INDEX_SIZE_ERR;
+ return;
+ }
+
+ // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly
+ if (isReadOnlyNode()) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return;
+ }
+}
+
+int CharacterData::maxCharacterOffset() const
+{
+ return (int)length();
+}
+
+bool CharacterData::rendererIsNeeded(RenderStyle *style)
+{
+ if (!m_data || m_data->length() == 0)
+ return false;
+ return EventTargetNode::rendererIsNeeded(style);
+}
+
+bool CharacterData::offsetInCharacters() const
+{
+ return true;
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/CharacterData.h b/WebCore/dom/CharacterData.h
new file mode 100644
index 0000000..da89a95
--- /dev/null
+++ b/WebCore/dom/CharacterData.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef CharacterData_h
+#define CharacterData_h
+
+#include "EventTargetNode.h"
+
+namespace WebCore {
+
+class CharacterData : public EventTargetNode {
+public:
+ CharacterData(Document*, const String& text);
+ CharacterData(Document*);
+ virtual ~CharacterData();
+
+ // DOM methods & attributes for CharacterData
+
+ String data() const { return m_data; }
+ void setData(const String&, ExceptionCode&);
+ unsigned length() const { return m_data->length(); }
+ String substringData(unsigned offset, unsigned count, ExceptionCode&);
+ void appendData(const String&, ExceptionCode&);
+ void insertData(unsigned offset, const String&, ExceptionCode&);
+ void deleteData(unsigned offset, unsigned count, ExceptionCode&);
+ void replaceData(unsigned offset, unsigned count, const String &arg, ExceptionCode&);
+
+ bool containsOnlyWhitespace() const;
+
+ // DOM methods overridden from parent classes
+
+ virtual String nodeValue() const;
+ virtual void setNodeValue(const String&, ExceptionCode&);
+
+ // Other methods (not part of DOM)
+
+ virtual bool isCharacterDataNode() const { return true; }
+ virtual int maxCharacterOffset() const;
+ StringImpl* string() { return m_data.get(); }
+ virtual void checkCharDataOperation(unsigned offset, ExceptionCode&);
+
+ virtual bool offsetInCharacters() const;
+ virtual bool rendererIsNeeded(RenderStyle*);
+
+protected:
+ RefPtr<StringImpl> m_data;
+
+ void dispatchModifiedEvent(StringImpl* oldValue);
+};
+
+} // namespace WebCore
+
+#endif // CharacterData_h
+
diff --git a/WebCore/dom/CharacterData.idl b/WebCore/dom/CharacterData.idl
new file mode 100644
index 0000000..74dc483
--- /dev/null
+++ b/WebCore/dom/CharacterData.idl
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module core {
+
+ interface [
+ GenerateConstructor,
+ InterfaceUUID=149159F4-D2BA-4040-8137-6BF6424C972A,
+ ImplementationUUID=E2095280-B9BD-446a-8C03-79F78417CDFF
+ ] CharacterData : EventTargetNode {
+
+ attribute [ConvertNullToNullString] DOMString data
+ setter raises(DOMException);
+
+ readonly attribute unsigned long length;
+
+ [ConvertNullStringTo=Null, OldStyleObjC] DOMString substringData(in [IsIndex] unsigned long offset,
+ in [IsIndex] unsigned long length)
+ raises(DOMException);
+
+ void appendData(in DOMString data)
+ raises(DOMException);
+
+ [OldStyleObjC] void insertData(in [IsIndex] unsigned long offset,
+ in DOMString data)
+ raises(DOMException);
+
+ [OldStyleObjC] void deleteData(in [IsIndex] unsigned long offset,
+ in [IsIndex] unsigned long length)
+ raises(DOMException);
+
+ [OldStyleObjC] void replaceData(in [IsIndex] unsigned long offset,
+ in [IsIndex] unsigned long length,
+ in DOMString data)
+ raises(DOMException);
+
+ };
+
+}
diff --git a/WebCore/dom/ChildNodeList.cpp b/WebCore/dom/ChildNodeList.cpp
new file mode 100644
index 0000000..4befe40
--- /dev/null
+++ b/WebCore/dom/ChildNodeList.cpp
@@ -0,0 +1,112 @@
+/**
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "ChildNodeList.h"
+
+#include "Node.h"
+
+namespace WebCore {
+
+ChildNodeList::ChildNodeList(PassRefPtr<Node> rootNode, DynamicNodeList::Caches* info)
+ : DynamicNodeList(rootNode, info, false)
+{
+}
+
+unsigned ChildNodeList::length() const
+{
+ if (m_caches->isLengthCacheValid)
+ return m_caches->cachedLength;
+
+ unsigned len = 0;
+ for (Node* n = m_rootNode->firstChild(); n; n = n->nextSibling())
+ len++;
+
+ m_caches->cachedLength = len;
+ m_caches->isLengthCacheValid = true;
+
+ return len;
+}
+
+Node* ChildNodeList::item(unsigned index) const
+{
+ unsigned int pos = 0;
+ Node* n = m_rootNode->firstChild();
+
+ if (m_caches->isItemCacheValid) {
+ if (index == m_caches->lastItemOffset)
+ return m_caches->lastItem;
+
+ int diff = index - m_caches->lastItemOffset;
+ unsigned dist = abs(diff);
+ if (dist < index) {
+ n = m_caches->lastItem;
+ pos = m_caches->lastItemOffset;
+ }
+ }
+
+ if (m_caches->isLengthCacheValid) {
+ if (index >= m_caches->cachedLength)
+ return 0;
+
+ int diff = index - pos;
+ unsigned dist = abs(diff);
+ if (dist > m_caches->cachedLength - 1 - index) {
+ n = m_rootNode->lastChild();
+ pos = m_caches->cachedLength - 1;
+ }
+ }
+
+ if (pos <= index) {
+ while (n && pos < index) {
+ n = n->nextSibling();
+ ++pos;
+ }
+ } else {
+ while (n && pos > index) {
+ n = n->previousSibling();
+ --pos;
+ }
+ }
+
+ if (n) {
+ m_caches->lastItem = n;
+ m_caches->lastItemOffset = pos;
+ m_caches->isItemCacheValid = true;
+ return n;
+ }
+
+ return 0;
+}
+
+bool ChildNodeList::nodeMatches(Node* testNode) const
+{
+ return testNode->parentNode() == m_rootNode;
+}
+
+void ChildNodeList::rootNodeChildrenChanged()
+{
+ // For child node lists, the common cache is reset in Node::notifyLocalNodeListsChildrenChanged()
+ ASSERT(!m_ownsCaches);
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/ChildNodeList.h b/WebCore/dom/ChildNodeList.h
new file mode 100644
index 0000000..efdc606
--- /dev/null
+++ b/WebCore/dom/ChildNodeList.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef ChildNodeList_h
+#define ChildNodeList_h
+
+#include "DynamicNodeList.h"
+
+namespace WebCore {
+
+ class ChildNodeList : public DynamicNodeList {
+ public:
+ ChildNodeList(PassRefPtr<Node> rootNode, DynamicNodeList::Caches*);
+
+ virtual unsigned length() const;
+ virtual Node* item(unsigned index) const;
+
+ virtual void rootNodeChildrenChanged();
+
+ protected:
+ virtual bool nodeMatches(Node*) const;
+ };
+
+} // namespace WebCore
+
+#endif // ChildNodeList_h
diff --git a/WebCore/dom/ClassNames.cpp b/WebCore/dom/ClassNames.cpp
new file mode 100644
index 0000000..d406198
--- /dev/null
+++ b/WebCore/dom/ClassNames.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2007 David Smith (catfish.man@gmail.com)
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "ClassNames.h"
+
+namespace WebCore {
+
+void ClassNames::parseClassAttribute(const String& classStr, const bool inCompatMode)
+{
+ if (!m_nameVector)
+ m_nameVector.set(new ClassNameVector);
+ else
+ m_nameVector->clear();
+
+ if (classStr.isEmpty())
+ return;
+
+ String classAttr = inCompatMode ? classStr.foldCase() : classStr;
+
+ const UChar* str = classAttr.characters();
+ const int length = classAttr.length();
+ int start = 0;
+ while (true) {
+ while (start < length && isClassWhitespace(str[start]))
+ ++start;
+ if (start >= length)
+ break;
+ int end = start + 1;
+ while (end < length && !isClassWhitespace(str[end]))
+ ++end;
+
+ m_nameVector->append(AtomicString(str + start, end - start));
+
+ start = end + 1;
+ }
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/ClassNames.h b/WebCore/dom/ClassNames.h
new file mode 100644
index 0000000..2bee7bd
--- /dev/null
+++ b/WebCore/dom/ClassNames.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef ClassNames_h
+#define ClassNames_h
+
+#include "AtomicString.h"
+#include <wtf/Vector.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+ class ClassNames {
+ typedef Vector<AtomicString, 8> ClassNameVector;
+ public:
+ ClassNames()
+ {
+ }
+
+ bool contains(const AtomicString& str) const
+ {
+ if (!m_nameVector)
+ return false;
+
+ size_t size = m_nameVector->size();
+ for (size_t i = 0; i < size; ++i) {
+ if (m_nameVector->at(i) == str)
+ return true;
+ }
+
+ return false;
+ }
+
+ void parseClassAttribute(const String&, const bool inCompatMode);
+
+ size_t size() const { return m_nameVector ? m_nameVector->size() : 0; }
+ void clear() { if (m_nameVector) m_nameVector->clear(); }
+ const AtomicString& operator[](size_t i) const { ASSERT(m_nameVector); return m_nameVector->at(i); }
+
+ private:
+ OwnPtr<ClassNameVector> m_nameVector;
+ };
+
+ inline static bool isClassWhitespace(UChar c)
+ {
+ return c == ' ' || c == '\r' || c == '\n' || c == '\t' || c == '\f';
+ }
+
+} // namespace WebCore
+
+#endif // ClassNames_h
diff --git a/WebCore/dom/ClassNodeList.cpp b/WebCore/dom/ClassNodeList.cpp
new file mode 100644
index 0000000..eb1f837
--- /dev/null
+++ b/WebCore/dom/ClassNodeList.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 David Smith (catfish.man@gmail.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "ClassNodeList.h"
+
+#include "Document.h"
+#include "Element.h"
+#include "Node.h"
+
+namespace WebCore {
+
+ClassNodeList::ClassNodeList(PassRefPtr<Node> rootNode, const String& classNames, DynamicNodeList::Caches* caches)
+ : DynamicNodeList(rootNode, caches, true)
+{
+ m_classNames.parseClassAttribute(classNames, m_rootNode->document()->inCompatMode());
+}
+
+bool ClassNodeList::nodeMatches(Node* testNode) const
+{
+ if (!testNode->isElementNode())
+ return false;
+
+ if (!testNode->hasClass())
+ return false;
+
+ if (!m_classNames.size())
+ return false;
+
+ const ClassNames& classes = *static_cast<Element*>(testNode)->getClassNames();
+ for (size_t i = 0; i < m_classNames.size(); ++i) {
+ if (!classes.contains(m_classNames[i]))
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/ClassNodeList.h b/WebCore/dom/ClassNodeList.h
new file mode 100644
index 0000000..947e346
--- /dev/null
+++ b/WebCore/dom/ClassNodeList.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 David Smith (catfish.man@gmail.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 ClassNodeList_h
+#define ClassNodeList_h
+
+#include "ClassNames.h"
+#include "DynamicNodeList.h"
+
+namespace WebCore {
+
+ class String;
+
+ class ClassNodeList : public DynamicNodeList {
+ public:
+ ClassNodeList(PassRefPtr<Node> rootNode, const String& classNames, DynamicNodeList::Caches*);
+
+ private:
+ virtual bool nodeMatches(Node*) const;
+
+ ClassNames m_classNames;
+ };
+
+} // namespace WebCore
+
+#endif // ClassNodeList_h
diff --git a/WebCore/dom/Clipboard.cpp b/WebCore/dom/Clipboard.cpp
new file mode 100755
index 0000000..4c808d1
--- /dev/null
+++ b/WebCore/dom/Clipboard.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2006, 2007 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Clipboard.h"
+
+#include "DOMImplementation.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "Image.h"
+#include "PluginInfoStore.h"
+
+namespace WebCore {
+
+Clipboard::Clipboard(ClipboardAccessPolicy policy, bool isForDragging)
+ : RefCounted<Clipboard>(0)
+ , m_policy(policy)
+ , m_dragStarted(false)
+ , m_forDragging(isForDragging)
+ , m_dragImage(0)
+{
+}
+
+void Clipboard::setAccessPolicy(ClipboardAccessPolicy policy)
+{
+ // once you go numb, can never go back
+ ASSERT(m_policy != ClipboardNumb || policy == ClipboardNumb);
+ m_policy = policy;
+}
+
+// These "conversion" methods are called by both WebCore and WebKit, and never make sense to JS, so we don't
+// worry about security for these. They don't allow access to the pasteboard anyway.
+
+static DragOperation dragOpFromIEOp(const String& op)
+{
+ // yep, it's really just this fixed set
+ if (op == "none")
+ return DragOperationNone;
+ if (op == "copy")
+ return DragOperationCopy;
+ if (op == "link")
+ return DragOperationLink;
+ if (op == "move")
+ return DragOperationGeneric;
+ if (op == "copyLink")
+ return (DragOperation)(DragOperationCopy | DragOperationLink);
+ if (op == "copyMove")
+ return (DragOperation)(DragOperationCopy | DragOperationGeneric | DragOperationMove);
+ if (op == "linkMove")
+ return (DragOperation)(DragOperationLink | DragOperationGeneric | DragOperationMove);
+ if (op == "all")
+ return DragOperationEvery;
+ return DragOperationPrivate; // really a marker for "no conversion"
+}
+
+static String IEOpFromDragOp(DragOperation op)
+{
+ bool moveSet = !!((DragOperationGeneric | DragOperationMove) & op);
+
+ if ((moveSet && (op & DragOperationCopy) && (op & DragOperationLink))
+ || (op == DragOperationEvery))
+ return "all";
+ if (moveSet && (op & DragOperationCopy))
+ return "copyMove";
+ if (moveSet && (op & DragOperationLink))
+ return "linkMove";
+ if ((op & DragOperationCopy) && (op & DragOperationLink))
+ return "copyLink";
+ if (moveSet)
+ return "move";
+ if (op & DragOperationCopy)
+ return "copy";
+ if (op & DragOperationLink)
+ return "link";
+ return "none";
+}
+
+bool Clipboard::sourceOperation(DragOperation& op) const
+{
+ if (m_effectAllowed.isNull())
+ return false;
+ op = dragOpFromIEOp(m_effectAllowed);
+ return true;
+}
+
+bool Clipboard::destinationOperation(DragOperation& op) const
+{
+ if (m_dropEffect.isNull())
+ return false;
+ op = dragOpFromIEOp(m_dropEffect);
+ return true;
+}
+
+void Clipboard::setSourceOperation(DragOperation op)
+{
+ m_effectAllowed = IEOpFromDragOp(op);
+}
+
+void Clipboard::setDestinationOperation(DragOperation op)
+{
+ m_dropEffect = IEOpFromDragOp(op);
+}
+
+void Clipboard::setDropEffect(const String &effect)
+{
+ if (m_policy == ClipboardReadable || m_policy == ClipboardTypesReadable) {
+ m_dropEffect = effect;
+ }
+}
+
+void Clipboard::setEffectAllowed(const String &effect)
+{
+ if (m_policy == ClipboardWritable)
+ m_effectAllowed = effect;
+}
+
+}
diff --git a/WebCore/dom/Clipboard.h b/WebCore/dom/Clipboard.h
new file mode 100644
index 0000000..5491c25
--- /dev/null
+++ b/WebCore/dom/Clipboard.h
@@ -0,0 +1,112 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Clipboard_h
+#define Clipboard_h
+
+#include <wtf/HashSet.h>
+#include "AtomicString.h"
+#include "ClipboardAccessPolicy.h"
+#include "DragActions.h"
+#include "DragImage.h"
+#include "IntPoint.h"
+#include "Node.h"
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+ class CachedImage;
+ class Element;
+ class Frame;
+ class Image;
+ class KURL;
+ class Range;
+ class String;
+
+ // State available during IE's events for drag and drop and copy/paste
+ class Clipboard : public RefCounted<Clipboard> {
+ public:
+ Clipboard(ClipboardAccessPolicy policy, bool isForDragging);
+ virtual ~Clipboard() { }
+
+ // Is this operation a drag-drop or a copy-paste?
+ bool isForDragging() const { return m_forDragging; }
+
+ String dropEffect() const { return m_dropEffect; }
+ void setDropEffect(const String&);
+ String effectAllowed() const { return m_effectAllowed; }
+ void setEffectAllowed(const String&);
+
+ virtual void clearData(const String& type) = 0;
+ virtual void clearAllData() = 0;
+ virtual String getData(const String& type, bool& success) const = 0;
+ virtual bool setData(const String& type, const String& data) = 0;
+
+ // extensions beyond IE's API
+ virtual HashSet<String> types() const = 0;
+
+ IntPoint dragLocation() const { return m_dragLoc; }
+ CachedImage* dragImage() const { return m_dragImage; }
+ virtual void setDragImage(CachedImage*, const IntPoint&) = 0;
+ Node* dragImageElement() { return m_dragImageElement.get(); }
+ virtual void setDragImageElement(Node*, const IntPoint&) = 0;
+
+ //Provides the DOM specified
+ virtual DragImageRef createDragImage(IntPoint& dragLoc) const = 0;
+ virtual void declareAndWriteDragImage(Element*, const KURL&, const String& title, Frame*) = 0;
+ virtual void writeURL(const KURL&, const String&, Frame*) = 0;
+ virtual void writeRange(Range*, Frame*) = 0;
+
+ virtual bool hasData() = 0;
+
+ void setAccessPolicy(ClipboardAccessPolicy);
+
+ bool sourceOperation(DragOperation&) const;
+ bool destinationOperation(DragOperation&) const;
+ void setSourceOperation(DragOperation);
+ void setDestinationOperation(DragOperation);
+
+ void setDragHasStarted() { m_dragStarted = true; }
+
+ protected:
+ ClipboardAccessPolicy policy() const { return m_policy; }
+ bool dragStarted() const { return m_dragStarted; }
+
+ private:
+ ClipboardAccessPolicy m_policy;
+ String m_dropEffect;
+ String m_effectAllowed;
+ bool m_dragStarted;
+
+ protected:
+ bool m_forDragging;
+ IntPoint m_dragLoc;
+ CachedImage* m_dragImage;
+ RefPtr<Node> m_dragImageElement;
+ };
+
+} // namespace WebCore
+
+#endif // Clipboard_h
diff --git a/WebCore/dom/ClipboardAccessPolicy.h b/WebCore/dom/ClipboardAccessPolicy.h
new file mode 100644
index 0000000..7a54009
--- /dev/null
+++ b/WebCore/dom/ClipboardAccessPolicy.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 ClipboardAccessPolicy_h
+#define ClipboardAccessPolicy_h
+
+namespace WebCore {
+
+enum ClipboardAccessPolicy {
+ ClipboardNumb, ClipboardImageWritable, ClipboardWritable, ClipboardTypesReadable, ClipboardReadable
+};
+
+} // namespace
+
+#endif
diff --git a/WebCore/dom/ClipboardEvent.cpp b/WebCore/dom/ClipboardEvent.cpp
new file mode 100644
index 0000000..f6c4333
--- /dev/null
+++ b/WebCore/dom/ClipboardEvent.cpp
@@ -0,0 +1,44 @@
+/**
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2003, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "ClipboardEvent.h"
+
+namespace WebCore {
+
+ClipboardEvent::ClipboardEvent()
+{
+}
+
+ClipboardEvent::ClipboardEvent(const AtomicString& eventType, bool canBubble, bool cancelable, Clipboard* clipboard)
+ : Event(eventType, canBubble, cancelable), m_clipboard(clipboard)
+{
+}
+
+bool ClipboardEvent::isClipboardEvent() const
+{
+ return true;
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/ClipboardEvent.h b/WebCore/dom/ClipboardEvent.h
new file mode 100644
index 0000000..69fc65b
--- /dev/null
+++ b/WebCore/dom/ClipboardEvent.h
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef ClipboardEvent_h
+#define ClipboardEvent_h
+
+#include "Clipboard.h"
+#include "Event.h"
+
+namespace WebCore {
+
+ class ClipboardEvent : public Event {
+ public:
+ ClipboardEvent();
+ ClipboardEvent(const AtomicString& type, bool canBubbleArg, bool cancelableArg, Clipboard* clipboardArg);
+
+ Clipboard* clipboard() const { return m_clipboard.get(); }
+
+ virtual bool isClipboardEvent() const;
+
+ private:
+ RefPtr<Clipboard> m_clipboard;
+ };
+
+} // namespace WebCore
+
+#endif // ClipboardEvent_h
diff --git a/WebCore/dom/Comment.cpp b/WebCore/dom/Comment.cpp
new file mode 100644
index 0000000..18bd89f
--- /dev/null
+++ b/WebCore/dom/Comment.cpp
@@ -0,0 +1,72 @@
+/**
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "Comment.h"
+
+#include "Document.h"
+
+namespace WebCore {
+
+Comment::Comment(Document* doc, const String& text)
+ : CharacterData(doc, text)
+{
+}
+
+Comment::Comment(Document* doc)
+ : CharacterData(doc)
+{
+}
+
+Comment::~Comment()
+{
+}
+
+String Comment::nodeName() const
+{
+ return commentAtom.string();
+}
+
+Node::NodeType Comment::nodeType() const
+{
+ return COMMENT_NODE;
+}
+
+PassRefPtr<Node> Comment::cloneNode(bool /*deep*/)
+{
+ return document()->createComment(m_data);
+}
+
+// DOM Section 1.1.1
+bool Comment::childTypeAllowed(NodeType)
+{
+ return false;
+}
+
+String Comment::toString() const
+{
+ // FIXME: We need to substitute entity references here.
+ return "<!--" + nodeValue() + "-->";
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/Comment.h b/WebCore/dom/Comment.h
new file mode 100644
index 0000000..9e480e4
--- /dev/null
+++ b/WebCore/dom/Comment.h
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Comment_h
+#define Comment_h
+
+#include "CharacterData.h"
+
+namespace WebCore {
+
+class Comment : public CharacterData
+{
+public:
+ Comment(Document*, const String &_text);
+ Comment(Document*);
+ virtual ~Comment();
+
+ // DOM methods overridden from parent classes
+ virtual String nodeName() const;
+ virtual NodeType nodeType() const;
+ virtual PassRefPtr<Node> cloneNode(bool deep);
+
+ // Other methods (not part of DOM)
+ virtual bool isCommentNode() const { return true; }
+ virtual bool childTypeAllowed(NodeType);
+
+ virtual String toString() const;
+};
+
+} // namespace WebCore
+
+#endif // Comment_h
diff --git a/WebCore/dom/Comment.idl b/WebCore/dom/Comment.idl
new file mode 100644
index 0000000..a89f0e7
--- /dev/null
+++ b/WebCore/dom/Comment.idl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module core {
+
+ interface [
+ GenerateConstructor,
+ InterfaceUUID=5D16069F-7E6B-4b28-8647-C36B2ED81ED1,
+ ImplementationUUID=CB55DB55-411F-451f-97C6-284B99E77F8E
+ ] Comment : CharacterData {
+ };
+
+}
diff --git a/WebCore/dom/ContainerNode.cpp b/WebCore/dom/ContainerNode.cpp
new file mode 100644
index 0000000..7103d72
--- /dev/null
+++ b/WebCore/dom/ContainerNode.cpp
@@ -0,0 +1,1001 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "ContainerNode.h"
+
+#include "DeleteButtonController.h"
+#include "Document.h"
+#include "Editor.h"
+#include "EventNames.h"
+#include "ExceptionCode.h"
+#include "FrameView.h"
+#include "InlineTextBox.h"
+#include "MutationEvent.h"
+#include "RenderTheme.h"
+#include "RootInlineBox.h"
+#include "SystemTime.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+using namespace EventNames;
+
+static void dispatchChildInsertionEvents(Node*, ExceptionCode&);
+static void dispatchChildRemovalEvents(Node*, ExceptionCode&);
+
+typedef Vector<std::pair<NodeCallback, RefPtr<Node> > > NodeCallbackQueue;
+static NodeCallbackQueue* s_postAttachCallbackQueue = 0;
+
+static size_t s_attachDepth = 0;
+
+ContainerNode::ContainerNode(Document* doc)
+ : EventTargetNode(doc), m_firstChild(0), m_lastChild(0)
+{
+}
+
+void ContainerNode::addChildNodesToDeletionQueue(Node*& head, Node*& tail, ContainerNode* container)
+{
+ // We have to tell all children that their parent has died.
+ Node* n;
+ Node* next;
+ for (n = container->firstChild(); n != 0; n = next) {
+ ASSERT(!n->m_deletionHasBegun);
+
+ next = n->nextSibling();
+ n->setPreviousSibling(0);
+ n->setNextSibling(0);
+ n->setParent(0);
+
+ if (!n->refCount()) {
+#ifndef NDEBUG
+ n->m_deletionHasBegun = true;
+#endif
+ // Add the node to the list of nodes to be deleted.
+ // Reuse the nextSibling pointer for this purpose.
+ if (tail)
+ tail->setNextSibling(n);
+ else
+ head = n;
+ tail = n;
+ } else if (n->inDocument())
+ n->removedFromDocument();
+ }
+ container->setFirstChild(0);
+ container->setLastChild(0);
+}
+
+void ContainerNode::removeAllChildren()
+{
+ // List of nodes to be deleted.
+ Node* head = 0;
+ Node* tail = 0;
+
+ addChildNodesToDeletionQueue(head, tail, this);
+
+ Node* n;
+ Node* next;
+ while ((n = head) != 0) {
+ ASSERT(n->m_deletionHasBegun);
+
+ next = n->nextSibling();
+ n->setNextSibling(0);
+
+ head = next;
+ if (next == 0)
+ tail = 0;
+
+ if (n->hasChildNodes())
+ addChildNodesToDeletionQueue(head, tail, static_cast<ContainerNode*>(n));
+
+ delete n;
+ }
+}
+
+ContainerNode::~ContainerNode()
+{
+ removeAllChildren();
+}
+
+
+Node* ContainerNode::virtualFirstChild() const
+{
+ return m_firstChild;
+}
+
+Node* ContainerNode::virtualLastChild() const
+{
+ return m_lastChild;
+}
+
+bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode& ec)
+{
+ // Check that this node is not "floating".
+ // If it is, it can be deleted as a side effect of sending mutation events.
+ ASSERT(refCount() || parent());
+
+ ec = 0;
+
+ // insertBefore(node, 0) is equivalent to appendChild(node)
+ if (!refChild)
+ return appendChild(newChild, ec);
+
+ // Make sure adding the new child is OK.
+ checkAddChild(newChild.get(), ec);
+ if (ec)
+ return false;
+
+ // NOT_FOUND_ERR: Raised if refChild is not a child of this node
+ if (refChild->parentNode() != this) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+
+ bool isFragment = newChild->nodeType() == DOCUMENT_FRAGMENT_NODE;
+
+ // If newChild is a DocumentFragment with no children; there's nothing to do.
+ // Just return true
+ if (isFragment && !newChild->firstChild())
+ return true;
+
+ // Now actually add the child(ren)
+ if (refChild->previousSibling() == newChild || refChild == newChild) // nothing to do
+ return true;
+
+ RefPtr<Node> next = refChild;
+ RefPtr<Node> prev = refChild->previousSibling();
+
+ int childCountDelta = 0;
+ RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild;
+ while (child) {
+ RefPtr<Node> nextChild = isFragment ? child->nextSibling() : 0;
+
+ // If child is already present in the tree, first remove it from the old location.
+ if (Node* oldParent = child->parentNode())
+ oldParent->removeChild(child.get(), ec);
+ if (ec)
+ return 0;
+
+ // FIXME: After sending the mutation events, "this" could be destroyed.
+ // We can prevent that by doing a "ref", but first we have to make sure
+ // that no callers call with ref count == 0 and parent = 0 (as of this
+ // writing, there are definitely callers who call that way).
+
+ // Due to arbitrary code running in response to a DOM mutation event it's
+ // possible that "next" is no longer a child of "this".
+ // It's also possible that "child" has been inserted elsewhere.
+ // In either of those cases, we'll just stop.
+ if (next->parentNode() != this)
+ break;
+ if (child->parentNode())
+ break;
+
+ ASSERT(!child->nextSibling());
+ ASSERT(!child->previousSibling());
+
+ childCountDelta++;
+
+ // Add child before "next".
+ forbidEventDispatch();
+ Node* prev = next->previousSibling();
+ ASSERT(m_lastChild != prev);
+ next->setPreviousSibling(child.get());
+ if (prev) {
+ ASSERT(m_firstChild != next);
+ ASSERT(prev->nextSibling() == next);
+ prev->setNextSibling(child.get());
+ } else {
+ ASSERT(m_firstChild == next);
+ m_firstChild = child.get();
+ }
+ child->setParent(this);
+ child->setPreviousSibling(prev);
+ child->setNextSibling(next.get());
+ allowEventDispatch();
+
+ // Dispatch the mutation events.
+ dispatchChildInsertionEvents(child.get(), ec);
+
+ // Add child to the rendering tree.
+ if (attached() && !child->attached() && child->parent() == this)
+ child->attach();
+
+ child = nextChild.release();
+ }
+
+ document()->setDocumentChanged(true);
+ if (childCountDelta)
+ childrenChanged(false, prev.get(), next.get(), childCountDelta);
+ dispatchSubtreeModifiedEvent();
+ return true;
+}
+
+bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode& ec)
+{
+ // Check that this node is not "floating".
+ // If it is, it can be deleted as a side effect of sending mutation events.
+ ASSERT(refCount() || parent());
+
+ ec = 0;
+
+ if (oldChild == newChild) // nothing to do
+ return true;
+
+ // Make sure replacing the old child with the new is ok
+ checkReplaceChild(newChild.get(), oldChild, ec);
+ if (ec)
+ return false;
+
+ // NOT_FOUND_ERR: Raised if oldChild is not a child of this node.
+ if (!oldChild || oldChild->parentNode() != this) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+
+ RefPtr<Node> prev = oldChild->previousSibling();
+ RefPtr<Node> next = oldChild->nextSibling();
+
+ // Remove the node we're replacing
+ RefPtr<Node> removedChild = oldChild;
+ removeChild(oldChild, ec);
+ if (ec)
+ return false;
+
+ // FIXME: After sending the mutation events, "this" could be destroyed.
+ // We can prevent that by doing a "ref", but first we have to make sure
+ // that no callers call with ref count == 0 and parent = 0 (as of this
+ // writing, there are definitely callers who call that way).
+
+ bool isFragment = newChild->nodeType() == DOCUMENT_FRAGMENT_NODE;
+
+ // Add the new child(ren)
+ int childCountDelta = 0;
+ RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild;
+ while (child) {
+ // If the new child is already in the right place, we're done.
+ if (prev && (prev == child || prev == child->previousSibling()))
+ break;
+
+ // For a fragment we have more children to do.
+ RefPtr<Node> nextChild = isFragment ? child->nextSibling() : 0;
+
+ // Remove child from its old position.
+ if (Node* oldParent = child->parentNode())
+ oldParent->removeChild(child.get(), ec);
+ if (ec)
+ return 0;
+
+ // Due to arbitrary code running in response to a DOM mutation event it's
+ // possible that "prev" is no longer a child of "this".
+ // It's also possible that "child" has been inserted elsewhere.
+ // In either of those cases, we'll just stop.
+ if (prev && prev->parentNode() != this)
+ break;
+ if (child->parentNode())
+ break;
+
+ childCountDelta++;
+
+ ASSERT(!child->nextSibling());
+ ASSERT(!child->previousSibling());
+
+ // Add child after "prev".
+ forbidEventDispatch();
+ Node* next;
+ if (prev) {
+ next = prev->nextSibling();
+ ASSERT(m_firstChild != next);
+ prev->setNextSibling(child.get());
+ } else {
+ next = m_firstChild;
+ m_firstChild = child.get();
+ }
+ if (next) {
+ ASSERT(m_lastChild != prev);
+ ASSERT(next->previousSibling() == prev);
+ next->setPreviousSibling(child.get());
+ } else {
+ ASSERT(m_lastChild == prev);
+ m_lastChild = child.get();
+ }
+ child->setParent(this);
+ child->setPreviousSibling(prev.get());
+ child->setNextSibling(next);
+ allowEventDispatch();
+
+ // Dispatch the mutation events
+ dispatchChildInsertionEvents(child.get(), ec);
+
+ // Add child to the rendering tree
+ if (attached() && !child->attached() && child->parent() == this)
+ child->attach();
+
+ prev = child;
+ child = nextChild.release();
+ }
+
+ document()->setDocumentChanged(true);
+ if (childCountDelta)
+ childrenChanged(false, prev.get(), next.get(), childCountDelta);
+ dispatchSubtreeModifiedEvent();
+ return true;
+}
+
+void ContainerNode::willRemove()
+{
+ for (Node *n = m_firstChild; n != 0; n = n->nextSibling())
+ n->willRemove();
+ EventTargetNode::willRemove();
+}
+
+static ExceptionCode willRemoveChild(Node *child)
+{
+ ExceptionCode ec = 0;
+
+ // fire removed from document mutation events.
+ dispatchChildRemovalEvents(child, ec);
+ if (ec)
+ return ec;
+
+ if (child->attached())
+ child->willRemove();
+
+ return 0;
+}
+
+bool ContainerNode::removeChild(Node* oldChild, ExceptionCode& ec)
+{
+ // Check that this node is not "floating".
+ // If it is, it can be deleted as a side effect of sending mutation events.
+ ASSERT(refCount() || parent());
+
+ ec = 0;
+
+ // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+ if (isReadOnlyNode()) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return false;
+ }
+
+ // NOT_FOUND_ERR: Raised if oldChild is not a child of this node.
+ if (!oldChild || oldChild->parentNode() != this) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+
+ RefPtr<Node> child = oldChild;
+
+ // dispatch pre-removal mutation events
+ if (document()->hasListenerType(Document::DOMNODEREMOVED_LISTENER)) {
+ EventTargetNodeCast(child.get())->dispatchEvent(new MutationEvent(DOMNodeRemovedEvent, true, false,
+ this, String(), String(), String(), 0), ec, true);
+ if (ec)
+ return false;
+ }
+
+ ec = willRemoveChild(child.get());
+ if (ec)
+ return false;
+
+ // Mutation events might have moved this child into a different parent.
+ if (child->parentNode() != this) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+
+ document()->removeFocusedNodeOfSubtree(child.get());
+
+ // FIXME: After sending the mutation events, "this" could be destroyed.
+ // We can prevent that by doing a "ref", but first we have to make sure
+ // that no callers call with ref count == 0 and parent = 0 (as of this
+ // writing, there are definitely callers who call that way).
+
+ forbidEventDispatch();
+
+ // Remove from rendering tree
+ if (child->attached())
+ child->detach();
+
+ // Remove the child
+ Node *prev, *next;
+ prev = child->previousSibling();
+ next = child->nextSibling();
+
+ if (next)
+ next->setPreviousSibling(prev);
+ if (prev)
+ prev->setNextSibling(next);
+ if (m_firstChild == child)
+ m_firstChild = next;
+ if (m_lastChild == child)
+ m_lastChild = prev;
+
+ child->setPreviousSibling(0);
+ child->setNextSibling(0);
+ child->setParent(0);
+
+ allowEventDispatch();
+
+ document()->setDocumentChanged(true);
+
+ // Dispatch post-removal mutation events
+ childrenChanged(false, prev, next, -1);
+ dispatchSubtreeModifiedEvent();
+
+ if (child->inDocument())
+ child->removedFromDocument();
+ else
+ child->removedFromTree(true);
+
+ return child;
+}
+
+// this differs from other remove functions because it forcibly removes all the children,
+// regardless of read-only status or event exceptions, e.g.
+bool ContainerNode::removeChildren()
+{
+ if (!m_firstChild)
+ return false;
+
+ Node* n;
+
+ // do any prep work needed before actually starting to detach
+ // and remove... e.g. stop loading frames, fire unload events
+ for (n = m_firstChild; n; n = n->nextSibling())
+ willRemoveChild(n);
+
+ // exclude this node when looking for removed focusedNode since only children will be removed
+ document()->removeFocusedNodeOfSubtree(this, true);
+
+ forbidEventDispatch();
+ int childCountDelta = 0;
+ while ((n = m_firstChild) != 0) {
+ childCountDelta--;
+
+ Node *next = n->nextSibling();
+
+ n->ref();
+
+ // Remove the node from the tree before calling detach or removedFromDocument (4427024, 4129744)
+ n->setPreviousSibling(0);
+ n->setNextSibling(0);
+ n->setParent(0);
+
+ m_firstChild = next;
+ if (n == m_lastChild)
+ m_lastChild = 0;
+
+ if (n->attached())
+ n->detach();
+
+ if (n->inDocument())
+ n->removedFromDocument();
+
+ n->deref();
+ }
+ allowEventDispatch();
+
+ // Dispatch a single post-removal mutation event denoting a modified subtree.
+ childrenChanged(false, 0, 0, childCountDelta);
+ dispatchSubtreeModifiedEvent();
+
+ return true;
+}
+
+bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec)
+{
+ // Check that this node is not "floating".
+ // If it is, it can be deleted as a side effect of sending mutation events.
+ ASSERT(refCount() || parent());
+
+ ec = 0;
+
+ // Make sure adding the new child is ok
+ checkAddChild(newChild.get(), ec);
+ if (ec)
+ return 0;
+
+ if (newChild == m_lastChild) // nothing to do
+ return newChild;
+
+ bool isFragment = newChild->nodeType() == DOCUMENT_FRAGMENT_NODE;
+
+ // If newChild is a DocumentFragment with no children.... there's nothing to do.
+ // Just return the document fragment
+ if (isFragment && !newChild->firstChild())
+ return true;
+
+ // Now actually add the child(ren)
+ int childCountDelta = 0;
+ RefPtr<Node> prev = lastChild();
+ RefPtr<Node> child = isFragment ? newChild->firstChild() : newChild;
+ while (child) {
+ // For a fragment we have more children to do.
+ RefPtr<Node> nextChild = isFragment ? child->nextSibling() : 0;
+
+ // If child is already present in the tree, first remove it
+ if (Node* oldParent = child->parentNode()) {
+ oldParent->removeChild(child.get(), ec);
+ if (ec)
+ return 0;
+
+ // If the child has a parent again, just stop what we're doing, because
+ // that means someone is doing something with DOM mutation -- can't re-parent
+ // a child that already has a parent.
+ if (child->parentNode())
+ break;
+ }
+
+ // Append child to the end of the list
+ childCountDelta++;
+ forbidEventDispatch();
+ child->setParent(this);
+ if (m_lastChild) {
+ child->setPreviousSibling(m_lastChild);
+ m_lastChild->setNextSibling(child.get());
+ } else
+ m_firstChild = child.get();
+ m_lastChild = child.get();
+ allowEventDispatch();
+
+ // Dispatch the mutation events
+ dispatchChildInsertionEvents(child.get(), ec);
+
+ // Add child to the rendering tree
+ if (attached() && !child->attached() && child->parent() == this)
+ child->attach();
+
+ child = nextChild.release();
+ }
+
+ document()->setDocumentChanged(true);
+ childrenChanged(false, prev.get(), 0, childCountDelta);
+ dispatchSubtreeModifiedEvent();
+ return true;
+}
+
+bool ContainerNode::hasChildNodes() const
+{
+ return m_firstChild;
+}
+
+ContainerNode* ContainerNode::addChild(PassRefPtr<Node> newChild)
+{
+ // This function is only used during parsing.
+ // It does not send any DOM mutation events.
+
+ // Check for consistency with DTD, but only when parsing HTML.
+ if (document()->isHTMLDocument() && !childAllowed(newChild.get()))
+ return 0;
+
+ forbidEventDispatch();
+ newChild->setParent(this);
+ Node* last = m_lastChild;
+ if (m_lastChild) {
+ newChild->setPreviousSibling(m_lastChild);
+ m_lastChild->setNextSibling(newChild.get());
+ } else
+ m_firstChild = newChild.get();
+ m_lastChild = newChild.get();
+ allowEventDispatch();
+
+ document()->incDOMTreeVersion();
+ if (inDocument())
+ newChild->insertedIntoDocument();
+ childrenChanged(true, last, 0, 1);
+
+ if (newChild->isElementNode())
+ return static_cast<ContainerNode*>(newChild.get());
+ return this;
+}
+
+void ContainerNode::suspendPostAttachCallbacks()
+{
+ ++s_attachDepth;
+}
+
+void ContainerNode::resumePostAttachCallbacks()
+{
+ if (s_attachDepth == 1 && s_postAttachCallbackQueue)
+ dispatchPostAttachCallbacks();
+ --s_attachDepth;
+}
+
+void ContainerNode::queuePostAttachCallback(NodeCallback callback, Node* node)
+{
+ if (!s_postAttachCallbackQueue)
+ s_postAttachCallbackQueue = new NodeCallbackQueue;
+
+ s_postAttachCallbackQueue->append(std::pair<NodeCallback, RefPtr<Node> >(callback, node));
+}
+
+void ContainerNode::dispatchPostAttachCallbacks()
+{
+ // We recalculate size() each time through the loop because a callback
+ // can add more callbacks to the end of the queue.
+ for (size_t i = 0; i < s_postAttachCallbackQueue->size(); ++i) {
+ std::pair<NodeCallback, RefPtr<Node> >& pair = (*s_postAttachCallbackQueue)[i];
+ NodeCallback callback = pair.first;
+ Node* node = pair.second.get();
+
+ callback(node);
+ }
+ s_postAttachCallbackQueue->clear();
+}
+
+void ContainerNode::attach()
+{
+ ++s_attachDepth;
+
+ for (Node* child = m_firstChild; child; child = child->nextSibling())
+ child->attach();
+ EventTargetNode::attach();
+
+ if (s_attachDepth == 1 && s_postAttachCallbackQueue)
+ dispatchPostAttachCallbacks();
+ --s_attachDepth;
+}
+
+void ContainerNode::detach()
+{
+ for (Node* child = m_firstChild; child; child = child->nextSibling())
+ child->detach();
+ EventTargetNode::detach();
+}
+
+void ContainerNode::insertedIntoDocument()
+{
+ EventTargetNode::insertedIntoDocument();
+ for (Node *child = m_firstChild; child; child = child->nextSibling())
+ child->insertedIntoDocument();
+}
+
+void ContainerNode::removedFromDocument()
+{
+ EventTargetNode::removedFromDocument();
+ for (Node *child = m_firstChild; child; child = child->nextSibling())
+ child->removedFromDocument();
+}
+
+void ContainerNode::insertedIntoTree(bool deep)
+{
+ EventTargetNode::insertedIntoTree(deep);
+ if (deep) {
+ for (Node *child = m_firstChild; child; child = child->nextSibling())
+ child->insertedIntoTree(deep);
+ }
+}
+
+void ContainerNode::removedFromTree(bool deep)
+{
+ EventTargetNode::removedFromTree(deep);
+ if (deep) {
+ for (Node *child = m_firstChild; child; child = child->nextSibling())
+ child->removedFromTree(deep);
+ }
+}
+
+void ContainerNode::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
+{
+ Node::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
+ if (document()->hasNodeLists())
+ notifyNodeListsChildrenChanged();
+}
+
+void ContainerNode::cloneChildNodes(ContainerNode *clone)
+{
+ // disable the delete button so it's elements are not serialized into the markup
+ if (document()->frame())
+ document()->frame()->editor()->deleteButtonController()->disable();
+ ExceptionCode ec = 0;
+ for (Node* n = firstChild(); n && !ec; n = n->nextSibling())
+ clone->appendChild(n->cloneNode(true), ec);
+ if (document()->frame())
+ document()->frame()->editor()->deleteButtonController()->enable();
+}
+
+bool ContainerNode::getUpperLeftCorner(int &xPos, int &yPos) const
+{
+ if (!renderer())
+ return false;
+ RenderObject *o = renderer();
+ RenderObject *p = o;
+
+ xPos = yPos = 0;
+ if (!o->isInline() || o->isReplaced()) {
+ o->absolutePosition(xPos, yPos);
+ return true;
+ }
+
+ // find the next text/image child, to get a position
+ while(o) {
+ p = o;
+ if (o->firstChild())
+ o = o->firstChild();
+ else if(o->nextSibling())
+ o = o->nextSibling();
+ else {
+ RenderObject *next = 0;
+ while (!next && o->parent()) {
+ o = o->parent();
+ next = o->nextSibling();
+ }
+ o = next;
+
+ if (!o)
+ break;
+ }
+
+ if (!o->isInline() || o->isReplaced()) {
+ o->absolutePosition(xPos, yPos);
+ return true;
+ }
+
+ if (p->element() && p->element() == this && o->isText() && !o->isBR() && !static_cast<RenderText*>(o)->firstTextBox()) {
+ // do nothing - skip unrendered whitespace that is a child or next sibling of the anchor
+ } else if ((o->isText() && !o->isBR()) || o->isReplaced()) {
+ o->container()->absolutePosition(xPos, yPos);
+ if (o->isText() && static_cast<RenderText *>(o)->firstTextBox()) {
+ xPos += static_cast<RenderText *>(o)->minXPos();
+ yPos += static_cast<RenderText *>(o)->firstTextBox()->root()->topOverflow();
+ } else {
+ xPos += o->xPos();
+ yPos += o->yPos();
+ }
+ return true;
+ }
+ }
+
+ // If the target doesn't have any children or siblings that could be used to calculate the scroll position, we must be
+ // at the end of the document. Scroll to the bottom.
+ if (!o && document()->view()) {
+ yPos += document()->view()->contentsHeight();
+ return true;
+ }
+ return false;
+}
+
+bool ContainerNode::getLowerRightCorner(int &xPos, int &yPos) const
+{
+ if (!renderer())
+ return false;
+
+ RenderObject *o = renderer();
+ xPos = yPos = 0;
+ if (!o->isInline() || o->isReplaced())
+ {
+ o->absolutePosition(xPos, yPos);
+ xPos += o->width();
+ yPos += o->height() + o->borderTopExtra() + o->borderBottomExtra();
+ return true;
+ }
+ // find the last text/image child, to get a position
+ while(o) {
+ if(o->lastChild())
+ o = o->lastChild();
+ else if(o->previousSibling())
+ o = o->previousSibling();
+ else {
+ RenderObject *prev = 0;
+ while(!prev) {
+ o = o->parent();
+ if(!o) return false;
+ prev = o->previousSibling();
+ }
+ o = prev;
+ }
+ if (o->isText() || o->isReplaced()) {
+ o->container()->absolutePosition(xPos, yPos);
+ if (o->isText())
+ xPos += static_cast<RenderText *>(o)->minXPos() + o->width();
+ else
+ xPos += o->xPos()+o->width();
+ yPos += o->yPos()+o->height();
+ return true;
+ }
+ }
+ return true;
+}
+
+IntRect ContainerNode::getRect() const
+{
+ int xPos = 0, yPos = 0, xEnd = 0, yEnd = 0;
+ bool foundUpperLeft = getUpperLeftCorner(xPos,yPos);
+ bool foundLowerRight = getLowerRightCorner(xEnd,yEnd);
+
+ // If we've found one corner, but not the other,
+ // then we should just return a point at the corner that we did find.
+ if (foundUpperLeft != foundLowerRight)
+ {
+ if (foundUpperLeft) {
+ xEnd = xPos;
+ yEnd = yPos;
+ } else {
+ xPos = xEnd;
+ yPos = yEnd;
+ }
+ }
+
+ if (xEnd < xPos)
+ xEnd = xPos;
+ if (yEnd < yPos)
+ yEnd = yPos;
+
+ return IntRect(xPos, yPos, xEnd - xPos, yEnd - yPos);
+}
+
+void ContainerNode::setFocus(bool received)
+{
+ if (m_focused == received) return;
+
+ EventTargetNode::setFocus(received);
+
+ // note that we need to recalc the style
+ setChanged();
+}
+
+void ContainerNode::setActive(bool down, bool pause)
+{
+ if (down == active()) return;
+
+ EventTargetNode::setActive(down);
+
+ // note that we need to recalc the style
+ // FIXME: Move to Element
+ if (renderer()) {
+ bool reactsToPress = renderer()->style()->affectedByActiveRules();
+ if (reactsToPress)
+ setChanged();
+ if (renderer() && renderer()->style()->hasAppearance()) {
+ if (theme()->stateChanged(renderer(), PressedState))
+ reactsToPress = true;
+ }
+ if (reactsToPress && pause) {
+ // The delay here is subtle. It relies on an assumption, namely that the amount of time it takes
+ // to repaint the "down" state of the control is about the same time as it would take to repaint the
+ // "up" state. Once you assume this, you can just delay for 100ms - that time (assuming that after you
+ // leave this method, it will be about that long before the flush of the up state happens again).
+#ifdef HAVE_FUNC_USLEEP
+ double startTime = currentTime();
+#endif
+
+ // Ensure there are no pending changes
+ Document::updateDocumentsRendering();
+ // Do an immediate repaint.
+ if (renderer())
+ renderer()->repaint(true);
+
+ // FIXME: Find a substitute for usleep for Win32.
+ // Better yet, come up with a way of doing this that doesn't use this sort of thing at all.
+#ifdef HAVE_FUNC_USLEEP
+ // Now pause for a small amount of time (1/10th of a second from before we repainted in the pressed state)
+ double remainingTime = 0.1 - (currentTime() - startTime);
+ if (remainingTime > 0)
+ usleep(static_cast<useconds_t>(remainingTime * 1000000.0));
+#endif
+ }
+ }
+}
+
+void ContainerNode::setHovered(bool over)
+{
+ if (over == hovered()) return;
+
+ EventTargetNode::setHovered(over);
+
+ // note that we need to recalc the style
+ // FIXME: Move to Element
+ if (renderer()) {
+ if (renderer()->style()->affectedByHoverRules())
+ setChanged();
+ if (renderer() && renderer()->style()->hasAppearance())
+ theme()->stateChanged(renderer(), HoverState);
+ }
+}
+
+unsigned ContainerNode::childNodeCount() const
+{
+ unsigned count = 0;
+ Node *n;
+ for (n = firstChild(); n; n = n->nextSibling())
+ count++;
+ return count;
+}
+
+Node *ContainerNode::childNode(unsigned index) const
+{
+ unsigned i;
+ Node *n = firstChild();
+ for (i = 0; n != 0 && i < index; i++)
+ n = n->nextSibling();
+ return n;
+}
+
+static void dispatchChildInsertionEvents(Node* child, ExceptionCode& ec)
+{
+ ASSERT(!eventDispatchForbidden());
+
+ RefPtr<Node> c = child;
+ DocPtr<Document> doc = child->document();
+
+ if (c->parentNode() && c->parentNode()->inDocument())
+ c->insertedIntoDocument();
+ else
+ c->insertedIntoTree(true);
+
+ if (c->parentNode() &&
+ doc->hasListenerType(Document::DOMNODEINSERTED_LISTENER) &&
+ c->isEventTargetNode()) {
+ ec = 0;
+ EventTargetNodeCast(c.get())->dispatchEvent(new MutationEvent(DOMNodeInsertedEvent, true, false,
+ c->parentNode(), String(), String(), String(), 0), ec, true);
+ if (ec)
+ return;
+ }
+
+ // dispatch the DOMNodeInsertedIntoDocument event to all descendants
+ if (c->inDocument() && doc->hasListenerType(Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER))
+ for (; c; c = c->traverseNextNode(child)) {
+ if (!c->isEventTargetNode())
+ continue;
+
+ ec = 0;
+ EventTargetNodeCast(c.get())->dispatchEvent(new MutationEvent(DOMNodeInsertedIntoDocumentEvent, false, false,
+ 0, String(), String(), String(), 0), ec, true);
+ if (ec)
+ return;
+ }
+}
+
+static void dispatchChildRemovalEvents(Node* child, ExceptionCode& ec)
+{
+ RefPtr<Node> c = child;
+ DocPtr<Document> doc = child->document();
+
+ // update auxiliary doc info (e.g. iterators) to note that node is being removed
+ doc->notifyBeforeNodeRemoval(child); // ### use events instead
+
+ // dispatch pre-removal mutation events
+ if (c->parentNode() &&
+ doc->hasListenerType(Document::DOMNODEREMOVED_LISTENER) &&
+ c->isEventTargetNode()) {
+ ec = 0;
+ EventTargetNodeCast(c.get())->dispatchEvent(new MutationEvent(DOMNodeRemovedEvent, true, false,
+ c->parentNode(), String(), String(), String(), 0), ec, true);
+ if (ec)
+ return;
+ }
+
+ // dispatch the DOMNodeRemovedFromDocument event to all descendants
+ if (c->inDocument() && doc->hasListenerType(Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER))
+ for (; c; c = c->traverseNextNode(child)) {
+ if (!c->isEventTargetNode())
+ continue;
+ ec = 0;
+ EventTargetNodeCast(c.get())->dispatchEvent(new MutationEvent(DOMNodeRemovedFromDocumentEvent, false, false,
+ 0, String(), String(), String(), 0), ec, true);
+ if (ec)
+ return;
+ }
+}
+
+}
diff --git a/WebCore/dom/ContainerNode.h b/WebCore/dom/ContainerNode.h
new file mode 100644
index 0000000..9bc4634
--- /dev/null
+++ b/WebCore/dom/ContainerNode.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef ContainerNode_h
+#define ContainerNode_h
+
+#include "EventTargetNode.h"
+
+namespace WebCore {
+
+typedef void (*NodeCallback)(Node*);
+
+class ContainerNode : public EventTargetNode {
+public:
+ ContainerNode(Document*);
+ virtual ~ContainerNode();
+
+ Node* firstChild() const { return m_firstChild; }
+ Node* lastChild() const { return m_lastChild; }
+
+ virtual bool insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode&);
+ virtual bool replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode&);
+ virtual bool removeChild(Node* child, ExceptionCode&);
+ virtual bool appendChild(PassRefPtr<Node> newChild, ExceptionCode&);
+
+ virtual ContainerNode* addChild(PassRefPtr<Node>);
+ virtual bool hasChildNodes() const;
+ virtual void attach();
+ virtual void detach();
+ virtual void willRemove();
+ virtual IntRect getRect() const;
+ virtual void setFocus(bool = true);
+ virtual void setActive(bool active = true, bool pause = false);
+ virtual void setHovered(bool = true);
+ virtual unsigned childNodeCount() const;
+ virtual Node* childNode(unsigned index) const;
+
+ virtual void insertedIntoDocument();
+ virtual void removedFromDocument();
+ virtual void insertedIntoTree(bool deep);
+ virtual void removedFromTree(bool deep);
+ virtual void childrenChanged(bool createdByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
+
+ virtual bool removeChildren();
+
+ void removeAllChildren();
+
+ void cloneChildNodes(ContainerNode* clone);
+
+protected:
+ static void queuePostAttachCallback(NodeCallback, Node*);
+ static void suspendPostAttachCallbacks();
+ static void resumePostAttachCallbacks();
+
+ void setFirstChild(Node* child) { m_firstChild = child; }
+ void setLastChild(Node* child) { m_lastChild = child; }
+
+private:
+ static void dispatchPostAttachCallbacks();
+
+ virtual Node* virtualFirstChild() const;
+ virtual Node* virtualLastChild() const;
+
+ static void addChildNodesToDeletionQueue(Node*& head, Node*& tail, ContainerNode*);
+
+ bool getUpperLeftCorner(int& x, int& y) const;
+ bool getLowerRightCorner(int& x, int& y) const;
+
+ Node* m_firstChild;
+ Node* m_lastChild;
+};
+
+} // namespace WebCore
+
+#endif // ContainerNode_h
diff --git a/WebCore/dom/DOMCoreException.h b/WebCore/dom/DOMCoreException.h
new file mode 100644
index 0000000..48bf52c
--- /dev/null
+++ b/WebCore/dom/DOMCoreException.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2007 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 DOMCoreException_h
+#define DOMCodeException_h
+
+#include "ExceptionBase.h"
+
+namespace WebCore {
+
+ class DOMCoreException : public ExceptionBase {
+ public:
+ DOMCoreException(const ExceptionCodeDescription& description)
+ : ExceptionBase(description)
+ {
+ }
+ };
+
+} // namespace WebCore
+
+#endif // DOMCoreException_h
diff --git a/WebCore/dom/DOMCoreException.idl b/WebCore/dom/DOMCoreException.idl
new file mode 100644
index 0000000..c9ac356
--- /dev/null
+++ b/WebCore/dom/DOMCoreException.idl
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2007 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+module core {
+
+ interface [
+ GenerateConstructor
+ ] DOMCoreException {
+
+ readonly attribute unsigned short code;
+ readonly attribute DOMString name;
+ readonly attribute DOMString message;
+
+#if defined(LANGUAGE_JAVASCRIPT)
+ // Override in a Mozilla compatible format
+ [DontEnum] DOMString toString();
+#endif
+
+ // ExceptionCode
+ const unsigned short INDEX_SIZE_ERR = 1;
+ const unsigned short DOMSTRING_SIZE_ERR = 2;
+ const unsigned short HIERARCHY_REQUEST_ERR = 3;
+ const unsigned short WRONG_DOCUMENT_ERR = 4;
+ const unsigned short INVALID_CHARACTER_ERR = 5;
+ const unsigned short NO_DATA_ALLOWED_ERR = 6;
+ const unsigned short NO_MODIFICATION_ALLOWED_ERR = 7;
+ const unsigned short NOT_FOUND_ERR = 8;
+ const unsigned short NOT_SUPPORTED_ERR = 9;
+ const unsigned short INUSE_ATTRIBUTE_ERR = 10;
+ // Introduced in DOM Level 2:
+ const unsigned short INVALID_STATE_ERR = 11;
+ // Introduced in DOM Level 2:
+ const unsigned short SYNTAX_ERR = 12;
+ // Introduced in DOM Level 2:
+ const unsigned short INVALID_MODIFICATION_ERR = 13;
+ // Introduced in DOM Level 2:
+ const unsigned short NAMESPACE_ERR = 14;
+ // Introduced in DOM Level 2:
+ const unsigned short INVALID_ACCESS_ERR = 15;
+ // Introduced in DOM Level 3:
+ const unsigned short VALIDATION_ERR = 16;
+ // Introduced in DOM Level 3:
+ const unsigned short TYPE_MISMATCH_ERR = 17;
+ };
+
+}
diff --git a/WebCore/dom/DOMImplementation.cpp b/WebCore/dom/DOMImplementation.cpp
new file mode 100644
index 0000000..db277d5
--- /dev/null
+++ b/WebCore/dom/DOMImplementation.cpp
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig (sam@webkit.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "DOMImplementation.h"
+
+#include "CSSStyleSheet.h"
+#include "DocumentType.h"
+#include "Element.h"
+#include "ExceptionCode.h"
+#include "Frame.h"
+#include "FTPDirectoryDocument.h"
+#include "HTMLDocument.h"
+#include "HTMLNames.h"
+#include "HTMLViewSourceDocument.h"
+#include "Image.h"
+#include "ImageDocument.h"
+#include "MediaList.h"
+#include "MIMETypeRegistry.h"
+#include "Page.h"
+#include "PluginDocument.h"
+#include "PluginInfoStore.h"
+#include "RegularExpression.h"
+#include "Settings.h"
+#include "TextDocument.h"
+#include "XMLNames.h"
+
+#if ENABLE(SVG)
+#include "SVGNames.h"
+#include "SVGDocument.h"
+#endif
+
+namespace WebCore {
+
+// FIXME: An implementation of this is still waiting for me to understand the distinction between
+// a "malformed" qualified name and one with bad characters in it. For example, is a second colon
+// an illegal character or a malformed qualified name? This will determine both what parameters
+// this function needs to take and exactly what it will do. Should also be exported so that
+// Element can use it too.
+static bool qualifiedNameIsMalformed(const String&)
+{
+ return false;
+}
+
+#if ENABLE(SVG)
+
+static void addString(HashSet<String, CaseFoldingHash>& set, const char* string)
+{
+ set.add(string);
+}
+
+static bool isSVG10Feature(const String &feature)
+{
+ static bool initialized = false;
+ static HashSet<String, CaseFoldingHash> svgFeatures;
+ if (!initialized) {
+#if ENABLE(SVG_USE) && ENABLE(SVG_FOREIGN_OBJECT) && ENABLE(SVG_FILTER) && ENABLE(SVG_FONTS)
+ addString(svgFeatures, "svg");
+ addString(svgFeatures, "svg.static");
+#endif
+// addString(svgFeatures, "svg.animation");
+// addString(svgFeatures, "svg.dynamic");
+// addString(svgFeatures, "svg.dom.animation");
+// addString(svgFeatures, "svg.dom.dynamic");
+#if ENABLE(SVG_USE) && ENABLE(SVG_FOREIGN_OBJECT) && ENABLE(SVG_FILTER) && ENABLE(SVG_FONTS)
+ addString(svgFeatures, "dom");
+ addString(svgFeatures, "dom.svg");
+ addString(svgFeatures, "dom.svg.static");
+#endif
+// addString(svgFeatures, "svg.all");
+// addString(svgFeatures, "dom.svg.all");
+ initialized = true;
+ }
+ return svgFeatures.contains(feature);
+}
+
+static bool isSVG11Feature(const String &feature)
+{
+ static bool initialized = false;
+ static HashSet<String, CaseFoldingHash> svgFeatures;
+ if (!initialized) {
+ // Sadly, we cannot claim to implement any of the SVG 1.1 generic feature sets
+ // lack of Font and Filter support.
+ // http://bugs.webkit.org/show_bug.cgi?id=15480
+#if ENABLE(SVG_USE) && ENABLE(SVG_FOREIGN_OBJECT) && ENABLE(SVG_FILTER) && ENABLE(SVG_FONTS)
+ addString(svgFeatures, "SVG");
+ addString(svgFeatures, "SVGDOM");
+ addString(svgFeatures, "SVG-static");
+ addString(svgFeatures, "SVGDOM-static");
+#endif
+// addString(svgFeatures, "SVG-animation);
+// addString(svgFeatures, "SVGDOM-animation);
+// addString(svgFeatures, "SVG-dynamic);
+// addString(svgFeatures, "SVGDOM-dynamic);
+ addString(svgFeatures, "CoreAttribute");
+#if ENABLE(SVG_USE)
+ addString(svgFeatures, "Structure");
+ addString(svgFeatures, "BasicStructure");
+#endif
+ addString(svgFeatures, "ContainerAttribute");
+ addString(svgFeatures, "ConditionalProcessing");
+ addString(svgFeatures, "Image");
+ addString(svgFeatures, "Style");
+ addString(svgFeatures, "ViewportAttribute");
+ addString(svgFeatures, "Shape");
+// addString(svgFeatures, "Text"); // requires altGlyph, bug 6426
+ addString(svgFeatures, "BasicText");
+ addString(svgFeatures, "PaintAttribute");
+ addString(svgFeatures, "BasicPaintAttribute");
+ addString(svgFeatures, "OpacityAttribute");
+ addString(svgFeatures, "GraphicsAttribute");
+ addString(svgFeatures, "BaseGraphicsAttribute");
+ addString(svgFeatures, "Marker");
+// addString(svgFeatures, "ColorProfile"); // requires color-profile, bug 6037
+ addString(svgFeatures, "Gradient");
+ addString(svgFeatures, "Pattern");
+ addString(svgFeatures, "Clip");
+ addString(svgFeatures, "BasicClip");
+ addString(svgFeatures, "Mask");
+#if ENABLE(SVG_FILTER)
+// addString(svgFeatures, "Filter");
+ addString(svgFeatures, "BasicFilter");
+#endif
+ addString(svgFeatures, "DocumentEventsAttribute");
+ addString(svgFeatures, "GraphicalEventsAttribute");
+// addString(svgFeatures, "AnimationEventsAttribute");
+ addString(svgFeatures, "Cursor");
+ addString(svgFeatures, "Hyperlinking");
+ addString(svgFeatures, "XlinkAttribute");
+ addString(svgFeatures, "ExternalResourcesRequired");
+// addString(svgFeatures, "View"); // buggy <view> support, bug 16962
+ addString(svgFeatures, "Script");
+// addString(svgFeatures, "Animation"); // <animate> support missing
+#if ENABLE(SVG_FONTS)
+ addString(svgFeatures, "Font");
+ addString(svgFeatures, "BasicFont");
+#endif
+#if ENABLE(SVG_FOREIGN_OBJECT)
+ addString(svgFeatures, "Extensibility");
+#endif
+ initialized = true;
+ }
+ return svgFeatures.contains(feature);
+}
+#endif
+
+DOMImplementation::~DOMImplementation()
+{
+}
+
+bool DOMImplementation::hasFeature (const String& feature, const String& version) const
+{
+ String lower = feature.lower();
+ if (lower == "core" || lower == "html" || lower == "xml" || lower == "xhtml")
+ return version.isEmpty() || version == "1.0" || version == "2.0";
+ if (lower == "css"
+ || lower == "css2"
+ || lower == "events"
+ || lower == "htmlevents"
+ || lower == "mouseevents"
+ || lower == "mutationevents"
+ || lower == "range"
+ || lower == "stylesheets"
+ || lower == "traversal"
+ || lower == "uievents"
+ || lower == "views")
+ return version.isEmpty() || version == "2.0";
+ if (lower == "xpath" || lower == "textevents")
+ return version.isEmpty() || version == "3.0";
+
+#if ENABLE(SVG)
+ if ((version.isEmpty() || version == "1.1") && feature.startsWith("http://www.w3.org/tr/svg11/feature#", false)) {
+ if (isSVG11Feature(feature.right(feature.length() - 35)))
+ return true;
+ }
+
+ if ((version.isEmpty() || version == "1.0") && feature.startsWith("org.w3c.", false)) {
+ if (isSVG10Feature(feature.right(feature.length() - 8)))
+ return true;
+ }
+#endif
+
+ return false;
+}
+
+PassRefPtr<DocumentType> DOMImplementation::createDocumentType(const String& qualifiedName,
+ const String& publicId, const String& systemId, ExceptionCode& ec)
+{
+ // Not mentioned in spec: throw NAMESPACE_ERR if no qualifiedName supplied
+ if (qualifiedName.isNull()) {
+ ec = NAMESPACE_ERR;
+ return 0;
+ }
+
+ // INVALID_CHARACTER_ERR: Raised if the specified qualified name contains an illegal character.
+ String prefix, localName;
+ if (!Document::parseQualifiedName(qualifiedName, prefix, localName)) {
+ ec = INVALID_CHARACTER_ERR;
+ return 0;
+ }
+
+ // NAMESPACE_ERR: Raised if the qualifiedName is malformed.
+ if (qualifiedNameIsMalformed(qualifiedName)) {
+ ec = NAMESPACE_ERR;
+ return 0;
+ }
+
+ ec = 0;
+ return new DocumentType(this, 0, qualifiedName, publicId, systemId);
+}
+
+DOMImplementation* DOMImplementation::getInterface(const String& /*feature*/) const
+{
+ // ###
+ return 0;
+}
+
+PassRefPtr<Document> DOMImplementation::createDocument(const String& namespaceURI,
+ const String& qualifiedName, DocumentType* doctype, ExceptionCode& ec)
+{
+ if (!qualifiedName.isEmpty()) {
+ // INVALID_CHARACTER_ERR: Raised if the specified qualified name contains an illegal character.
+ String prefix, localName;
+ if (!Document::parseQualifiedName(qualifiedName, prefix, localName)) {
+ ec = INVALID_CHARACTER_ERR;
+ return 0;
+ }
+
+ // NAMESPACE_ERR:
+ // - Raised if the qualifiedName is malformed,
+ // - if the qualifiedName has a prefix and the namespaceURI is null, or
+ // - if the qualifiedName has a prefix that is "xml" and the namespaceURI is different
+ // from "http://www.w3.org/XML/1998/namespace" [Namespaces].
+ int colonpos = qualifiedName.find(':');
+ if (qualifiedNameIsMalformed(qualifiedName) ||
+ (colonpos >= 0 && namespaceURI.isNull()) ||
+ (colonpos == 3 && qualifiedName[0] == 'x' && qualifiedName[1] == 'm' && qualifiedName[2] == 'l' &&
+#if ENABLE(SVG)
+ namespaceURI != SVGNames::svgNamespaceURI &&
+#endif
+ namespaceURI != XMLNames::xmlNamespaceURI)) {
+
+ ec = NAMESPACE_ERR;
+ return 0;
+ }
+ }
+
+ // WRONG_DOCUMENT_ERR: Raised if doctype has already been used with a different document or was
+ // created from a different implementation.
+ if (doctype && (doctype->document() || doctype->implementation() != this)) {
+ ec = WRONG_DOCUMENT_ERR;
+ return 0;
+ }
+
+ RefPtr<Document> doc;
+#if ENABLE(SVG)
+ if (namespaceURI == SVGNames::svgNamespaceURI)
+ doc = new SVGDocument(this, 0);
+ else
+#endif
+ if (namespaceURI == HTMLNames::xhtmlNamespaceURI)
+ doc = new Document(this, 0, true);
+ else
+ doc = new Document(this, 0);
+
+ // now get the interesting parts of the doctype
+ if (doctype)
+ doc->addChild(doctype);
+
+ if (!qualifiedName.isEmpty())
+ doc->addChild(doc->createElementNS(namespaceURI, qualifiedName, ec));
+
+ ec = 0;
+ return doc.release();
+}
+
+PassRefPtr<CSSStyleSheet> DOMImplementation::createCSSStyleSheet(const String&, const String& media, ExceptionCode& ec)
+{
+ // ### TODO : title should be set, and media could have wrong syntax, in which case we should generate an exception.
+ ec = 0;
+ CSSStyleSheet* const nullSheet = 0;
+ RefPtr<CSSStyleSheet> sheet = new CSSStyleSheet(nullSheet);
+ sheet->setMedia(new MediaList(sheet.get(), media, true));
+ return sheet.release();
+}
+
+PassRefPtr<Document> DOMImplementation::createDocument(Frame* frame)
+{
+ return new Document(this, frame);
+}
+
+PassRefPtr<HTMLDocument> DOMImplementation::createHTMLDocument(Frame* frame)
+{
+ return new HTMLDocument(this, frame);
+}
+
+DOMImplementation* DOMImplementation::instance()
+{
+ static RefPtr<DOMImplementation> i = new DOMImplementation;
+ return i.get();
+}
+
+bool DOMImplementation::isXMLMIMEType(const String& mimeType)
+{
+ if (mimeType == "text/xml" || mimeType == "application/xml" || mimeType == "text/xsl")
+ return true;
+ static const char* validChars = "[0-9a-zA-Z_\\-+~!$\\^{}|.%'`#&*]"; // per RFCs: 3023, 2045
+ static RegularExpression xmlTypeRegExp(String("^") + validChars + "+/" + validChars + "+\\+xml$");
+ return xmlTypeRegExp.match(mimeType) > -1;
+}
+
+bool DOMImplementation::isTextMIMEType(const String& mimeType)
+{
+ if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType) ||
+ (mimeType.startsWith("text/") && mimeType != "text/html" &&
+ mimeType != "text/xml" && mimeType != "text/xsl"))
+ return true;
+
+ return false;
+}
+
+PassRefPtr<HTMLDocument> DOMImplementation::createHTMLDocument(const String& title)
+{
+ RefPtr<HTMLDocument> d = new HTMLDocument(this, 0);
+ d->open();
+ d->write("<!doctype html><html><head><title>" + title + "</title></head><body></body></html>");
+ return d.release();
+}
+
+PassRefPtr<Document> DOMImplementation::createDocument(const String& type, Frame* frame, bool inViewSourceMode)
+{
+ if (inViewSourceMode) {
+ if (type == "text/html" || type == "application/xhtml+xml" || type == "image/svg+xml" || isTextMIMEType(type) || isXMLMIMEType(type))
+ return new HTMLViewSourceDocument(this, frame, type);
+ }
+
+ // Plugins cannot take HTML and XHTML from us, and we don't even need to initialize the plugin database for those.
+ if (type == "text/html")
+ return new HTMLDocument(this, frame);
+ if (type == "application/xhtml+xml")
+ return new Document(this, frame, true);
+
+#if ENABLE(FTPDIR)
+ // Plugins cannot take FTP from us either
+ if (type == "application/x-ftp-directory")
+ return new FTPDirectoryDocument(this, frame);
+#endif
+
+ // PDF is one image type for which a plugin can override built-in support.
+ // We do not want QuickTime to take over all image types, obviously.
+ if ((type == "application/pdf" || type == "text/pdf") && PluginInfoStore::supportsMIMEType(type))
+ return new PluginDocument(this, frame);
+ if (Image::supportsType(type))
+ return new ImageDocument(this, frame);
+ // Everything else except text/plain can be overridden by plugins. In particular, Adobe SVG Viewer should be used for SVG, if installed.
+ // Disallowing plug-ins to use text/plain prevents plug-ins from hijacking a fundamental type that the browser is expected to handle,
+ // and also serves as an optimization to prevent loading the plug-in database in the common case.
+ if (type != "text/plain" && PluginInfoStore::supportsMIMEType(type))
+ return new PluginDocument(this, frame);
+ if (isTextMIMEType(type))
+ return new TextDocument(this, frame);
+
+#if ENABLE(SVG)
+ if (type == "image/svg+xml") {
+ Settings* settings = frame ? frame->settings() : 0;
+ if (!settings || !settings->usesDashboardBackwardCompatibilityMode())
+ return new SVGDocument(this, frame);
+ }
+#endif
+ if (isXMLMIMEType(type))
+ return new Document(this, frame);
+
+ return new HTMLDocument(this, frame);
+}
+
+}
diff --git a/WebCore/dom/DOMImplementation.h b/WebCore/dom/DOMImplementation.h
new file mode 100644
index 0000000..80b921c
--- /dev/null
+++ b/WebCore/dom/DOMImplementation.h
@@ -0,0 +1,76 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef DOMImplementation_h
+#define DOMImplementation_h
+
+#include <wtf/RefCounted.h>
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+class CSSStyleSheet;
+class Document;
+class DocumentType;
+class Frame;
+class HTMLDocument;
+class String;
+
+typedef int ExceptionCode;
+
+class DOMImplementation : public RefCounted<DOMImplementation> {
+public:
+ DOMImplementation() : RefCounted<DOMImplementation>(0) { }
+ virtual ~DOMImplementation();
+
+ // DOM methods & attributes for DOMImplementation
+ bool hasFeature(const String& feature, const String& version) const;
+ PassRefPtr<DocumentType> createDocumentType(const String& qualifiedName, const String& publicId, const String &systemId, ExceptionCode&);
+ PassRefPtr<Document> createDocument(const String& namespaceURI, const String& qualifiedName, DocumentType*, ExceptionCode&);
+
+ DOMImplementation* getInterface(const String& feature) const;
+
+ // From the DOMImplementationCSS interface
+ PassRefPtr<CSSStyleSheet> createCSSStyleSheet(const String& title, const String& media, ExceptionCode&);
+
+ // From the HTMLDOMImplementation interface
+ PassRefPtr<HTMLDocument> createHTMLDocument(const String& title);
+
+ // Other methods (not part of DOM)
+ PassRefPtr<Document> createDocument(const String& MIMEType, Frame*, bool inViewSourceMode);
+ PassRefPtr<Document> createDocument(Frame*);
+ PassRefPtr<HTMLDocument> createHTMLDocument(Frame*);
+
+ // Returns the static instance of this class - only one instance of this class should
+ // ever be present, and is used as a factory method for creating Document objects
+ static DOMImplementation* instance();
+
+ static bool isXMLMIMEType(const String& MIMEType);
+ static bool isTextMIMEType(const String& MIMEType);
+};
+
+} //namespace
+
+#endif
diff --git a/WebCore/dom/DOMImplementation.idl b/WebCore/dom/DOMImplementation.idl
new file mode 100644
index 0000000..43d8c33
--- /dev/null
+++ b/WebCore/dom/DOMImplementation.idl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module core {
+
+ interface [
+ GenerateConstructor,
+ InterfaceUUID=B0CC344F-963C-4acc-9FC6-EB22649345E5,
+ ImplementationUUID=9E835092-2CA3-426b-826B-8272A8105E49
+ ] DOMImplementation {
+
+ // DOM Level 1
+
+ [OldStyleObjC] boolean hasFeature(in DOMString feature,
+ in [ConvertNullToNullString] DOMString version);
+
+ // DOM Level 2
+
+ [OldStyleObjC] DocumentType createDocumentType(in DOMString qualifiedName,
+ in DOMString publicId,
+ in DOMString systemId)
+ raises(DOMException);
+ [OldStyleObjC] Document createDocument(in [ConvertNullToNullString] DOMString namespaceURI,
+ in [ConvertNullToNullString] DOMString qualifiedName,
+ in [ConvertNullToNullString] DocumentType doctype)
+ raises(DOMException);
+
+ // DOMImplementationCSS interface from DOM Level 2 CSS
+
+#if !defined(LANGUAGE_COM)
+ [OldStyleObjC] CSSStyleSheet createCSSStyleSheet(in DOMString title,
+ in DOMString media)
+ raises(DOMException);
+
+ // HTMLDOMImplementation interface from DOM Level 2 HTML
+
+ HTMLDocument createHTMLDocument(in DOMString title);
+#endif
+ };
+
+}
diff --git a/WebCore/dom/DocPtr.h b/WebCore/dom/DocPtr.h
new file mode 100644
index 0000000..9882017
--- /dev/null
+++ b/WebCore/dom/DocPtr.h
@@ -0,0 +1,115 @@
+// -*- mode: c++; c-basic-offset: 4 -*-
+/*
+ * This file is part of the DOM implementation for KDE.
+ * Copyright (C) 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef DocPtr_h
+#define DocPtr_h
+
+namespace WebCore {
+
+template <class T> class DocPtr {
+public:
+ DocPtr() : m_ptr(0) {}
+ DocPtr(T *ptr) : m_ptr(ptr) { if (ptr) ptr->selfOnlyRef(); }
+ DocPtr(const DocPtr &o) : m_ptr(o.m_ptr) { if (T *ptr = m_ptr) ptr->selfOnlyRef(); }
+ ~DocPtr() { if (T *ptr = m_ptr) ptr->selfOnlyDeref(); }
+
+ template <class U> DocPtr(const DocPtr<U> &o) : m_ptr(o.get()) { if (T *ptr = m_ptr) ptr->selfOnlyRef(); }
+
+ void resetSkippingRef(T *o) { m_ptr = o; }
+
+ T *get() const { return m_ptr; }
+
+ T &operator*() const { return *m_ptr; }
+ T *operator->() const { return m_ptr; }
+
+ bool operator!() const { return !m_ptr; }
+
+ // this type conversion operator allows implicit conversion to
+ // bool but not to other integer types
+
+ typedef T * (DocPtr::*UnspecifiedBoolType)() const;
+ operator UnspecifiedBoolType() const
+ {
+ return m_ptr ? &DocPtr::get : 0;
+ }
+
+ DocPtr &operator=(const DocPtr &);
+ DocPtr &operator=(T *);
+
+ private:
+ T *m_ptr;
+};
+
+template <class T> DocPtr<T> &DocPtr<T>::operator=(const DocPtr<T> &o)
+{
+ T *optr = o.m_ptr;
+ if (optr)
+ optr->selfOnlyRef();
+ if (T *ptr = m_ptr)
+ ptr->selfOnlyDeref();
+ m_ptr = optr;
+ return *this;
+}
+
+template <class T> inline DocPtr<T> &DocPtr<T>::operator=(T *optr)
+{
+ if (optr)
+ optr->selfOnlyRef();
+ if (T *ptr = m_ptr)
+ ptr->selfOnlyDeref();
+ m_ptr = optr;
+ return *this;
+}
+
+template <class T> inline bool operator==(const DocPtr<T> &a, const DocPtr<T> &b)
+{
+ return a.get() == b.get();
+}
+
+template <class T> inline bool operator==(const DocPtr<T> &a, const T *b)
+{
+ return a.get() == b;
+}
+
+template <class T> inline bool operator==(const T *a, const DocPtr<T> &b)
+{
+ return a == b.get();
+}
+
+template <class T> inline bool operator!=(const DocPtr<T> &a, const DocPtr<T> &b)
+{
+ return a.get() != b.get();
+}
+
+template <class T> inline bool operator!=(const DocPtr<T> &a, const T *b)
+{
+ return a.get() != b;
+}
+
+template <class T> inline bool operator!=(const T *a, const DocPtr<T> &b)
+{
+ return a != b.get();
+}
+
+} // namespace WebCore
+
+#endif // DocPtr_h
diff --git a/WebCore/dom/Document.cpp b/WebCore/dom/Document.cpp
new file mode 100644
index 0000000..f6de5de
--- /dev/null
+++ b/WebCore/dom/Document.cpp
@@ -0,0 +1,3830 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * (C) 2006 Alexey Proskuryakov (ap@webkit.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "Document.h"
+
+#include "AXObjectCache.h"
+#include "CDATASection.h"
+#include "CachedCSSStyleSheet.h"
+#include "CSSHelper.h"
+#include "CSSStyleSelector.h"
+#include "CSSStyleSheet.h"
+#include "CSSValueKeywords.h"
+#include "CString.h"
+#include "ClassNodeList.h"
+#include "Comment.h"
+#include "CookieJar.h"
+#include "DOMImplementation.h"
+#include "DocLoader.h"
+#include "DocumentFragment.h"
+#include "DocumentLoader.h"
+#include "DocumentType.h"
+#include "DOMWindow.h"
+#include "EditingText.h"
+#include "Editor.h"
+#include "EditorClient.h"
+#include "EntityReference.h"
+#include "Event.h"
+#include "EventHandler.h"
+#include "EventListener.h"
+#include "EventNames.h"
+#include "ExceptionCode.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "HTMLBodyElement.h"
+#include "HTMLDocument.h"
+#include "HTMLElementFactory.h"
+#include "HTMLFrameOwnerElement.h"
+#include "HTMLHeadElement.h"
+#include "HTMLImageLoader.h"
+#include "HTMLInputElement.h"
+#include "HTMLLinkElement.h"
+#include "HTMLMapElement.h"
+#include "HTMLNameCollection.h"
+#include "HTMLNames.h"
+#include "HTMLStyleElement.h"
+#include "HTMLTitleElement.h"
+#include "HTTPParsers.h"
+#include "HistoryItem.h"
+#include "HitTestRequest.h"
+#include "HitTestResult.h"
+#include "KeyboardEvent.h"
+#include "Logging.h"
+#include "MouseEvent.h"
+#include "MouseEventWithHitTestResults.h"
+#include "MutationEvent.h"
+#include "NameNodeList.h"
+#include "NodeFilter.h"
+#include "NodeIterator.h"
+#include "OverflowEvent.h"
+#include "Page.h"
+#include "PlatformKeyboardEvent.h"
+#include "ProcessingInstruction.h"
+#include "ProgressEvent.h"
+#include "RegisteredEventListener.h"
+#include "RegularExpression.h"
+#include "RenderArena.h"
+#include "RenderView.h"
+#include "RenderWidget.h"
+#include "SecurityOrigin.h"
+#include "SegmentedString.h"
+#include "SelectionController.h"
+#include "Settings.h"
+#include "StringHash.h"
+#include "StyleSheetList.h"
+#include "SystemTime.h"
+#include "TextEvent.h"
+#include "TextIterator.h"
+#include "TextResourceDecoder.h"
+#include "TreeWalker.h"
+#include "UIEvent.h"
+#include "WheelEvent.h"
+#include "XMLHttpRequest.h"
+#include "XMLTokenizer.h"
+#include "kjs_binding.h"
+#include "kjs_proxy.h"
+
+#if ENABLE(DATABASE)
+#include "Database.h"
+#include "DatabaseThread.h"
+#endif
+
+#if ENABLE(CROSS_DOCUMENT_MESSAGING)
+#include "MessageEvent.h"
+#endif
+
+#if ENABLE(XPATH)
+#include "XPathEvaluator.h"
+#include "XPathExpression.h"
+#include "XPathNSResolver.h"
+#include "XPathResult.h"
+#endif
+
+#if ENABLE(XSLT)
+#include "XSLTProcessor.h"
+#endif
+
+#if ENABLE(XBL)
+#include "XBLBindingManager.h"
+#endif
+
+#if ENABLE(SVG)
+#include "SVGDocumentExtensions.h"
+#include "SVGElementFactory.h"
+#include "SVGZoomEvent.h"
+#include "SVGStyleElement.h"
+#include "TimeScheduler.h"
+#endif
+
+using namespace std;
+using namespace WTF;
+using namespace Unicode;
+
+namespace WebCore {
+
+using namespace EventNames;
+using namespace HTMLNames;
+
+// #define INSTRUMENT_LAYOUT_SCHEDULING 1
+
+// This amount of time must have elapsed before we will even consider scheduling a layout without a delay.
+// FIXME: For faster machines this value can really be lowered to 200. 250 is adequate, but a little high
+// for dual G5s. :)
+static const int cLayoutScheduleThreshold = 250;
+
+// Use 1 to represent the document's default form.
+static HTMLFormElement* const defaultForm = reinterpret_cast<HTMLFormElement*>(1);
+
+// Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's
+static const unsigned PHI = 0x9e3779b9U;
+
+// DOM Level 2 says (letters added):
+//
+// a) Name start characters must have one of the categories Ll, Lu, Lo, Lt, Nl.
+// b) Name characters other than Name-start characters must have one of the categories Mc, Me, Mn, Lm, or Nd.
+// c) Characters in the compatibility area (i.e. with character code greater than #xF900 and less than #xFFFE) are not allowed in XML names.
+// d) Characters which have a font or compatibility decomposition (i.e. those with a "compatibility formatting tag" in field 5 of the database -- marked by field 5 beginning with a "<") are not allowed.
+// e) The following characters are treated as name-start characters rather than name characters, because the property file classifies them as Alphabetic: [#x02BB-#x02C1], #x0559, #x06E5, #x06E6.
+// f) Characters #x20DD-#x20E0 are excluded (in accordance with Unicode, section 5.14).
+// g) Character #x00B7 is classified as an extender, because the property list so identifies it.
+// h) Character #x0387 is added as a name character, because #x00B7 is its canonical equivalent.
+// i) Characters ':' and '_' are allowed as name-start characters.
+// j) Characters '-' and '.' are allowed as name characters.
+//
+// It also contains complete tables. If we decide it's better, we could include those instead of the following code.
+
+static inline bool isValidNameStart(UChar32 c)
+{
+ // rule (e) above
+ if ((c >= 0x02BB && c <= 0x02C1) || c == 0x559 || c == 0x6E5 || c == 0x6E6)
+ return true;
+
+ // rule (i) above
+ if (c == ':' || c == '_')
+ return true;
+
+ // rules (a) and (f) above
+ const uint32_t nameStartMask = Letter_Lowercase | Letter_Uppercase | Letter_Other | Letter_Titlecase | Number_Letter;
+ if (!(Unicode::category(c) & nameStartMask))
+ return false;
+
+ // rule (c) above
+ if (c >= 0xF900 && c < 0xFFFE)
+ return false;
+
+ // rule (d) above
+ DecompositionType decompType = decompositionType(c);
+ if (decompType == DecompositionFont || decompType == DecompositionCompat)
+ return false;
+
+ return true;
+}
+
+static inline bool isValidNamePart(UChar32 c)
+{
+ // rules (a), (e), and (i) above
+ if (isValidNameStart(c))
+ return true;
+
+ // rules (g) and (h) above
+ if (c == 0x00B7 || c == 0x0387)
+ return true;
+
+ // rule (j) above
+ if (c == '-' || c == '.')
+ return true;
+
+ // rules (b) and (f) above
+ const uint32_t otherNamePartMask = Mark_NonSpacing | Mark_Enclosing | Mark_SpacingCombining | Letter_Modifier | Number_DecimalDigit;
+ if (!(Unicode::category(c) & otherNamePartMask))
+ return false;
+
+ // rule (c) above
+ if (c >= 0xF900 && c < 0xFFFE)
+ return false;
+
+ // rule (d) above
+ DecompositionType decompType = decompositionType(c);
+ if (decompType == DecompositionFont || decompType == DecompositionCompat)
+ return false;
+
+ return true;
+}
+
+static Widget* widgetForNode(Node* focusedNode)
+ {
+ if (!focusedNode)
+ return 0;
+ RenderObject* renderer = focusedNode->renderer();
+ if (!renderer || !renderer->isWidget())
+ return 0;
+ return static_cast<RenderWidget*>(renderer)->widget();
+}
+
+static bool acceptsEditingFocus(Node *node)
+{
+ ASSERT(node);
+ ASSERT(node->isContentEditable());
+
+ Node *root = node->rootEditableElement();
+ Frame* frame = node->document()->frame();
+ if (!frame || !root)
+ return false;
+
+ return frame->editor()->shouldBeginEditing(rangeOfContents(root).get());
+}
+
+DeprecatedPtrList<Document>* Document::changedDocuments = 0;
+
+// FrameView might be 0
+Document::Document(DOMImplementation* impl, Frame* frame, bool isXHTML)
+ : ContainerNode(0)
+ , m_implementation(impl)
+ , m_domtree_version(0)
+ , m_styleSheets(new StyleSheetList(this))
+ , m_title("")
+ , m_titleSetExplicitly(false)
+ , m_imageLoadEventTimer(this, &Document::imageLoadEventTimerFired)
+ , m_updateFocusAppearanceTimer(this, &Document::updateFocusAppearanceTimerFired)
+#if ENABLE(XSLT)
+ , m_transformSource(0)
+#endif
+ , m_xmlVersion("1.0")
+ , m_xmlStandalone(false)
+#if ENABLE(XBL)
+ , m_bindingManager(new XBLBindingManager(this))
+#endif
+ , m_savedRenderer(0)
+ , m_secureForms(0)
+ , m_designMode(inherit)
+ , m_selfOnlyRefCount(0)
+#if ENABLE(SVG)
+ , m_svgExtensions(0)
+#endif
+ , m_hasDashboardRegions(false)
+ , m_dashboardRegionsDirty(false)
+ , m_accessKeyMapValid(false)
+ , m_createRenderers(true)
+ , m_inPageCache(false)
+ , m_isAllowedToLoadLocalResources(false)
+ , m_useSecureKeyboardEntryWhenActive(false)
+ , m_isXHTML(isXHTML)
+ , m_numNodeLists(0)
+#if ENABLE(DATABASE)
+ , m_hasOpenDatabases(false)
+#endif
+#if USE(LOW_BANDWIDTH_DISPLAY)
+ , m_inLowBandwidthDisplay(false)
+#endif
+{
+ m_document.resetSkippingRef(this);
+
+ m_printing = false;
+
+ m_frame = frame;
+ m_renderArena = 0;
+
+ m_axObjectCache = 0;
+
+ // FIXME: DocLoader probably no longer needs the frame argument
+ m_docLoader = new DocLoader(frame, this);
+
+ visuallyOrdered = false;
+ m_bParsing = false;
+ m_docChanged = false;
+ m_tokenizer = 0;
+ m_wellFormed = false;
+
+ setParseMode(Strict);
+
+ m_textColor = Color::black;
+ m_listenerTypes = 0;
+ m_inDocument = true;
+ m_inStyleRecalc = false;
+ m_closeAfterStyleRecalc = false;
+ m_usesDescendantRules = false;
+ m_usesSiblingRules = false;
+ m_usesFirstLineRules = false;
+ m_usesFirstLetterRules = false;
+ m_gotoAnchorNeededAfterStylesheetsLoad = false;
+
+ m_styleSelector = 0;
+ m_didCalculateStyleSelector = false;
+ m_pendingStylesheets = 0;
+ m_ignorePendingStylesheets = false;
+ m_hasNodesWithPlaceholderStyle = false;
+ m_pendingSheetLayout = NoLayoutWithPendingSheets;
+
+ m_cssTarget = 0;
+
+ resetLinkColor();
+ resetVisitedLinkColor();
+ resetActiveLinkColor();
+
+ m_processingLoadEvent = false;
+ m_startTime = currentTime();
+ m_overMinimumLayoutThreshold = false;
+
+ initSecurityOrigin();
+
+ static int docID = 0;
+ m_docID = docID++;
+}
+
+void Document::removedLastRef()
+{
+ ASSERT(!m_deletionHasBegun);
+ if (m_selfOnlyRefCount) {
+ // If removing a child removes the last self-only ref, we don't
+ // want the document to be destructed until after
+ // removeAllChildren returns, so we guard ourselves with an
+ // extra self-only ref.
+
+ DocPtr<Document> guard(this);
+
+ // We must make sure not to be retaining any of our children through
+ // these extra pointers or we will create a reference cycle.
+ m_docType = 0;
+ m_focusedNode = 0;
+ m_hoverNode = 0;
+ m_activeNode = 0;
+ m_titleElement = 0;
+ m_documentElement = 0;
+
+ removeAllChildren();
+
+ deleteAllValues(m_markers);
+ m_markers.clear();
+
+ delete m_tokenizer;
+ m_tokenizer = 0;
+
+#ifndef NDEBUG
+ m_inRemovedLastRefFunction = false;
+#endif
+ } else {
+#ifndef NDEBUG
+ m_deletionHasBegun = true;
+#endif
+ delete this;
+ }
+}
+
+Document::~Document()
+{
+ ASSERT(!renderer());
+ ASSERT(!m_inPageCache);
+ ASSERT(!m_savedRenderer);
+
+ removeAllEventListeners();
+
+#if ENABLE(SVG)
+ delete m_svgExtensions;
+#endif
+
+ XMLHttpRequest::detachRequests(this);
+ {
+ KJS::JSLock lock;
+ ScriptInterpreter::forgetAllDOMNodesForDocument(this);
+ }
+
+ if (m_docChanged && changedDocuments)
+ changedDocuments->remove(this);
+ delete m_tokenizer;
+ m_document.resetSkippingRef(0);
+ delete m_styleSelector;
+ delete m_docLoader;
+
+ if (m_renderArena) {
+ delete m_renderArena;
+ m_renderArena = 0;
+ }
+
+#if ENABLE(XSLT)
+ xmlFreeDoc((xmlDocPtr)m_transformSource);
+#endif
+
+#if ENABLE(XBL)
+ delete m_bindingManager;
+#endif
+
+ deleteAllValues(m_markers);
+
+ if (m_axObjectCache) {
+ delete m_axObjectCache;
+ m_axObjectCache = 0;
+ }
+ m_decoder = 0;
+
+ unsigned count = sizeof(m_nameCollectionInfo) / sizeof(m_nameCollectionInfo[0]);
+ for (unsigned i = 0; i < count; i++)
+ deleteAllValues(m_nameCollectionInfo[i]);
+
+#if ENABLE(DATABASE)
+ if (m_databaseThread) {
+ ASSERT(m_databaseThread->terminationRequested());
+ m_databaseThread = 0;
+ }
+#endif
+
+ if (m_styleSheets)
+ m_styleSheets->documentDestroyed();
+}
+
+void Document::resetLinkColor()
+{
+ m_linkColor = Color(0, 0, 238);
+}
+
+void Document::resetVisitedLinkColor()
+{
+ m_visitedLinkColor = Color(85, 26, 139);
+}
+
+void Document::resetActiveLinkColor()
+{
+ m_activeLinkColor.setNamedColor("red");
+}
+
+void Document::setDocType(PassRefPtr<DocumentType> docType)
+{
+ // This should never be called more than once.
+ // Note: This is not a public DOM method and can only be called by the parser.
+ ASSERT(!m_docType || !docType);
+ if (m_docType && docType)
+ return;
+ m_docType = docType;
+ if (m_docType)
+ m_docType->setDocument(this);
+ determineParseMode();
+}
+
+DOMImplementation* Document::implementation() const
+{
+ return m_implementation.get();
+}
+
+void Document::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
+{
+ ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
+
+ // Invalidate the document element we have cached in case it was replaced.
+ m_documentElement = 0;
+}
+
+Element* Document::documentElement() const
+{
+ if (!m_documentElement) {
+ Node* n = firstChild();
+ while (n && !n->isElementNode())
+ n = n->nextSibling();
+ m_documentElement = static_cast<Element*>(n);
+ }
+
+ return m_documentElement.get();
+}
+
+PassRefPtr<Element> Document::createElement(const String &name, ExceptionCode& ec)
+{
+ if (m_isXHTML) {
+ if (!isValidName(name)) {
+ ec = INVALID_CHARACTER_ERR;
+ return 0;
+ }
+
+ return HTMLElementFactory::createHTMLElement(AtomicString(name), this, 0, false);
+ } else
+ return createElementNS(nullAtom, name, ec);
+}
+
+PassRefPtr<DocumentFragment> Document::createDocumentFragment()
+{
+ return new DocumentFragment(document());
+}
+
+PassRefPtr<Text> Document::createTextNode(const String &data)
+{
+ return new Text(this, data);
+}
+
+PassRefPtr<Comment> Document::createComment (const String &data)
+{
+ return new Comment(this, data);
+}
+
+PassRefPtr<CDATASection> Document::createCDATASection(const String &data, ExceptionCode& ec)
+{
+ if (isHTMLDocument()) {
+ ec = NOT_SUPPORTED_ERR;
+ return 0;
+ }
+ return new CDATASection(this, data);
+}
+
+PassRefPtr<ProcessingInstruction> Document::createProcessingInstruction(const String &target, const String &data, ExceptionCode& ec)
+{
+ if (!isValidName(target)) {
+ ec = INVALID_CHARACTER_ERR;
+ return 0;
+ }
+ if (isHTMLDocument()) {
+ ec = NOT_SUPPORTED_ERR;
+ return 0;
+ }
+ return new ProcessingInstruction(this, target, data);
+}
+
+PassRefPtr<EntityReference> Document::createEntityReference(const String &name, ExceptionCode& ec)
+{
+ if (!isValidName(name)) {
+ ec = INVALID_CHARACTER_ERR;
+ return 0;
+ }
+ if (isHTMLDocument()) {
+ ec = NOT_SUPPORTED_ERR;
+ return 0;
+ }
+ return new EntityReference(this, name);
+}
+
+PassRefPtr<EditingText> Document::createEditingTextNode(const String &text)
+{
+ return new EditingText(this, text);
+}
+
+PassRefPtr<CSSStyleDeclaration> Document::createCSSStyleDeclaration()
+{
+ return new CSSMutableStyleDeclaration;
+}
+
+PassRefPtr<Node> Document::importNode(Node* importedNode, bool deep, ExceptionCode& ec)
+{
+ ec = 0;
+
+ if (!importedNode
+#if ENABLE(SVG)
+ || (importedNode->isSVGElement() && page() && page()->settings()->usesDashboardBackwardCompatibilityMode())
+#endif
+ ) {
+ ec = NOT_SUPPORTED_ERR;
+ return 0;
+ }
+
+ switch (importedNode->nodeType()) {
+ 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 = static_cast<Element*>(importedNode);
+ RefPtr<Element> newElement = createElementNS(oldElement->namespaceURI(), oldElement->tagQName().toString(), ec);
+
+ if (ec)
+ return 0;
+
+ NamedAttrMap* attrs = oldElement->attributes(true);
+ if (attrs) {
+ unsigned length = attrs->length();
+ for (unsigned i = 0; i < length; i++) {
+ Attribute* attr = attrs->attributeItem(i);
+ newElement->setAttribute(attr->name(), attr->value().impl(), ec);
+ if (ec)
+ return 0;
+ }
+ }
+
+ newElement->copyNonAttributeProperties(oldElement);
+
+ if (deep) {
+ for (Node* oldChild = oldElement->firstChild(); oldChild; oldChild = oldChild->nextSibling()) {
+ RefPtr<Node> newChild = importNode(oldChild, true, ec);
+ if (ec)
+ return 0;
+ newElement->appendChild(newChild.release(), ec);
+ if (ec)
+ return 0;
+ }
+ }
+
+ return newElement.release();
+ }
+ case ATTRIBUTE_NODE: {
+ RefPtr<Attr> newAttr = new Attr(0, this, static_cast<Attr*>(importedNode)->attr()->clone());
+ newAttr->createTextChild();
+ return newAttr.release();
+ }
+ case DOCUMENT_FRAGMENT_NODE: {
+ DocumentFragment* oldFragment = static_cast<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 0;
+ newFragment->appendChild(newChild.release(), ec);
+ if (ec)
+ return 0;
+ }
+ }
+
+ return newFragment.release();
+ }
+ case ENTITY_NODE:
+ case NOTATION_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:
+ break;
+ }
+
+ ec = NOT_SUPPORTED_ERR;
+ return 0;
+}
+
+
+PassRefPtr<Node> Document::adoptNode(PassRefPtr<Node> source, ExceptionCode& ec)
+{
+ if (!source) {
+ ec = NOT_SUPPORTED_ERR;
+ return 0;
+ }
+
+ if (source->isReadOnlyNode()) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return 0;
+ }
+
+ switch (source->nodeType()) {
+ case ENTITY_NODE:
+ case NOTATION_NODE:
+ case DOCUMENT_NODE:
+ case DOCUMENT_TYPE_NODE:
+ case XPATH_NAMESPACE_NODE:
+ ec = NOT_SUPPORTED_ERR;
+ return 0;
+ case ATTRIBUTE_NODE: {
+ Attr* attr = static_cast<Attr*>(source.get());
+ if (attr->ownerElement())
+ attr->ownerElement()->removeAttributeNode(attr, ec);
+ attr->m_attrWasSpecifiedOrElementHasRareData = true;
+ break;
+ }
+ default:
+ if (source->parentNode())
+ source->parentNode()->removeChild(source.get(), ec);
+ }
+
+ for (Node* node = source.get(); node; node = node->traverseNextNode(source.get()))
+ node->setDocument(this);
+
+ return source;
+}
+
+// FIXME: This should really be in a possible ElementFactory class
+PassRefPtr<Element> Document::createElement(const QualifiedName& qName, bool createdByParser, ExceptionCode& ec)
+{
+ RefPtr<Element> e;
+
+ // FIXME: Use registered namespaces and look up in a hash to find the right factory.
+ if (qName.namespaceURI() == xhtmlNamespaceURI)
+ e = HTMLElementFactory::createHTMLElement(qName.localName(), this, 0, createdByParser);
+#if ENABLE(SVG)
+ else if (qName.namespaceURI() == SVGNames::svgNamespaceURI)
+ e = SVGElementFactory::createSVGElement(qName, this, createdByParser);
+#endif
+
+ if (!e)
+ e = new Element(qName, document());
+
+ if (e && !qName.prefix().isNull()) {
+ ec = 0;
+ e->setPrefix(qName.prefix(), ec);
+ if (ec)
+ return 0;
+ }
+
+ return e.release();
+}
+
+PassRefPtr<Element> Document::createElementNS(const String &_namespaceURI, const String &qualifiedName, ExceptionCode& ec)
+{
+ String prefix, localName;
+ if (!parseQualifiedName(qualifiedName, prefix, localName)) {
+ ec = INVALID_CHARACTER_ERR;
+ return 0;
+ }
+
+ RefPtr<Element> e;
+ QualifiedName qName = QualifiedName(AtomicString(prefix), AtomicString(localName), AtomicString(_namespaceURI));
+
+ return createElement(qName, false, ec);
+}
+
+Element *Document::getElementById(const AtomicString& elementId) const
+{
+ if (elementId.length() == 0)
+ return 0;
+
+ Element *element = m_elementsById.get(elementId.impl());
+ if (element)
+ return element;
+
+ if (m_duplicateIds.contains(elementId.impl())) {
+ // We know there's at least one node with this id, but we don't know what the first one is.
+ for (Node *n = traverseNextNode(); n != 0; n = n->traverseNextNode()) {
+ if (n->isElementNode()) {
+ element = static_cast<Element*>(n);
+ if (element->hasID() && element->getAttribute(idAttr) == elementId) {
+ m_duplicateIds.remove(elementId.impl());
+ m_elementsById.set(elementId.impl(), element);
+ return element;
+ }
+ }
+ }
+ ASSERT_NOT_REACHED();
+ }
+ return 0;
+}
+
+String Document::readyState() const
+{
+ if (Frame* f = frame()) {
+ if (f->loader()->isComplete())
+ return "complete";
+ if (parsing())
+ return "loading";
+ return "loaded";
+ // FIXME: What does "interactive" mean?
+ // FIXME: Missing support for "uninitialized".
+ }
+ return String();
+}
+
+String Document::inputEncoding() const
+{
+ if (TextResourceDecoder* d = decoder())
+ return d->encoding().name();
+ return String();
+}
+
+String Document::defaultCharset() const
+{
+ if (Settings* settings = this->settings())
+ return settings->defaultTextEncodingName();
+ return String();
+}
+
+void Document::setCharset(const String& charset)
+{
+ if (!decoder())
+ return;
+ decoder()->setEncoding(charset, TextResourceDecoder::UserChosenEncoding);
+}
+
+void Document::setXMLVersion(const String& version, ExceptionCode& ec)
+{
+ // FIXME: also raise NOT_SUPPORTED_ERR if the version is set to a value that is not supported by this Document.
+ if (!implementation()->hasFeature("XML", String())) {
+ ec = NOT_SUPPORTED_ERR;
+ return;
+ }
+
+ m_xmlVersion = version;
+}
+
+void Document::setXMLStandalone(bool standalone, ExceptionCode& ec)
+{
+ if (!implementation()->hasFeature("XML", String())) {
+ ec = NOT_SUPPORTED_ERR;
+ return;
+ }
+
+ m_xmlStandalone = standalone;
+}
+
+KURL Document::documentURI() const
+{
+ return m_baseURL;
+}
+
+void Document::setDocumentURI(const String& uri)
+{
+ m_baseURL = KURL(uri);
+}
+
+KURL Document::baseURI() const
+{
+ return m_baseURL;
+}
+
+Element* Document::elementFromPoint(int x, int y) const
+{
+ if (!renderer())
+ return 0;
+
+ HitTestRequest request(true, true);
+ HitTestResult result(IntPoint(x, y));
+ renderer()->layer()->hitTest(request, result);
+
+ Node* n = result.innerNode();
+ while (n && !n->isElementNode())
+ n = n->parentNode();
+ if (n)
+ n = n->shadowAncestorNode();
+ return static_cast<Element*>(n);
+}
+
+void Document::addElementById(const AtomicString& elementId, Element* element)
+{
+ typedef HashMap<AtomicStringImpl*, Element*>::iterator iterator;
+ if (!m_duplicateIds.contains(elementId.impl())) {
+ // Fast path. The ID is not already in m_duplicateIds, so we assume that it's
+ // also not already in m_elementsById and do an add. If that add succeeds, we're done.
+ pair<iterator, bool> addResult = m_elementsById.add(elementId.impl(), element);
+ if (addResult.second)
+ return;
+ // The add failed, so this ID was already cached in m_elementsById.
+ // There are multiple elements with this ID. Remove the m_elementsById
+ // cache for this ID so getElementById searches for it next time it is called.
+ m_elementsById.remove(addResult.first);
+ m_duplicateIds.add(elementId.impl());
+ } else {
+ // There are multiple elements with this ID. If it exists, remove the m_elementsById
+ // cache for this ID so getElementById searches for it next time it is called.
+ iterator cachedItem = m_elementsById.find(elementId.impl());
+ if (cachedItem != m_elementsById.end()) {
+ m_elementsById.remove(cachedItem);
+ m_duplicateIds.add(elementId.impl());
+ }
+ }
+ m_duplicateIds.add(elementId.impl());
+}
+
+void Document::removeElementById(const AtomicString& elementId, Element* element)
+{
+ if (m_elementsById.get(elementId.impl()) == element)
+ m_elementsById.remove(elementId.impl());
+ else
+ m_duplicateIds.remove(elementId.impl());
+}
+
+Element* Document::getElementByAccessKey(const String& key) const
+{
+ if (key.isEmpty())
+ return 0;
+ if (!m_accessKeyMapValid) {
+ for (Node* n = firstChild(); n; n = n->traverseNextNode()) {
+ if (!n->isElementNode())
+ continue;
+ Element* element = static_cast<Element*>(n);
+ const AtomicString& accessKey = element->getAttribute(accesskeyAttr);
+ if (!accessKey.isEmpty())
+ m_elementsByAccessKey.set(accessKey.impl(), element);
+ }
+ m_accessKeyMapValid = true;
+ }
+ return m_elementsByAccessKey.get(key.impl());
+}
+
+void Document::updateTitle()
+{
+ if (Frame* f = frame())
+ f->loader()->setTitle(m_title);
+}
+
+void Document::setTitle(const String& title, Element* titleElement)
+{
+ if (!titleElement) {
+ // Title set by JavaScript -- overrides any title elements.
+ m_titleSetExplicitly = true;
+ if (!isHTMLDocument())
+ m_titleElement = 0;
+ else if (!m_titleElement) {
+ if (HTMLElement* headElement = head()) {
+ ExceptionCode ec = 0;
+ m_titleElement = createElement("title", ec);
+ ASSERT(!ec);
+ headElement->appendChild(m_titleElement, ec);
+ ASSERT(!ec);
+ }
+ }
+ } else if (titleElement != m_titleElement) {
+ if (m_titleElement || m_titleSetExplicitly)
+ // Only allow the first title element to change the title -- others have no effect.
+ return;
+ m_titleElement = titleElement;
+ }
+
+ if (m_title == title)
+ return;
+
+ m_title = title;
+ updateTitle();
+
+ if (m_titleSetExplicitly && m_titleElement && m_titleElement->hasTagName(titleTag))
+ static_cast<HTMLTitleElement*>(m_titleElement.get())->setText(m_title);
+}
+
+void Document::removeTitle(Element* titleElement)
+{
+ if (m_titleElement != titleElement)
+ return;
+
+ m_titleElement = 0;
+ m_titleSetExplicitly = false;
+
+ // Update title based on first title element in the head, if one exists.
+ if (HTMLElement* headElement = head()) {
+ for (Node* e = headElement->firstChild(); e; e = e->nextSibling())
+ if (e->hasTagName(titleTag)) {
+ HTMLTitleElement* titleElement = static_cast<HTMLTitleElement*>(e);
+ setTitle(titleElement->text(), titleElement);
+ break;
+ }
+ }
+
+ if (!m_titleElement && !m_title.isEmpty()) {
+ m_title = "";
+ updateTitle();
+ }
+}
+
+String Document::nodeName() const
+{
+ return "#document";
+}
+
+Node::NodeType Document::nodeType() const
+{
+ return DOCUMENT_NODE;
+}
+
+FrameView* Document::view() const
+{
+ return m_frame ? m_frame->view() : 0;
+}
+
+Page* Document::page() const
+{
+ return m_frame ? m_frame->page() : 0;
+}
+
+Settings* Document::settings() const
+{
+ return m_frame ? m_frame->settings() : 0;
+}
+
+PassRefPtr<Range> Document::createRange()
+{
+ return new Range(this);
+}
+
+PassRefPtr<NodeIterator> Document::createNodeIterator(Node* root, unsigned whatToShow,
+ PassRefPtr<NodeFilter> filter, bool expandEntityReferences, ExceptionCode& ec)
+{
+ if (!root) {
+ ec = NOT_SUPPORTED_ERR;
+ return 0;
+ }
+ return new NodeIterator(root, whatToShow, filter, expandEntityReferences);
+}
+
+PassRefPtr<TreeWalker> Document::createTreeWalker(Node *root, unsigned whatToShow,
+ PassRefPtr<NodeFilter> filter, bool expandEntityReferences, ExceptionCode& ec)
+{
+ if (!root) {
+ ec = NOT_SUPPORTED_ERR;
+ return 0;
+ }
+ return new TreeWalker(root, whatToShow, filter, expandEntityReferences);
+}
+
+void Document::setDocumentChanged(bool b)
+{
+ if (b) {
+ if (!m_docChanged) {
+ if (!changedDocuments)
+ changedDocuments = new DeprecatedPtrList<Document>;
+ changedDocuments->append(this);
+ }
+ if (m_accessKeyMapValid) {
+ m_accessKeyMapValid = false;
+ m_elementsByAccessKey.clear();
+ }
+ } else {
+ if (m_docChanged && changedDocuments)
+ changedDocuments->remove(this);
+ }
+
+ m_docChanged = b;
+}
+
+void Document::recalcStyle(StyleChange change)
+{
+ // we should not enter style recalc while painting
+ if (frame() && frame()->isPainting()) {
+ ASSERT(!frame()->isPainting());
+ return;
+ }
+
+ if (m_inStyleRecalc)
+ return; // Guard against re-entrancy. -dwh
+
+ m_inStyleRecalc = true;
+ suspendPostAttachCallbacks();
+
+ ASSERT(!renderer() || renderArena());
+ if (!renderer() || !renderArena())
+ goto bail_out;
+
+ if (change == Force) {
+ // style selector may set this again during recalc
+ m_hasNodesWithPlaceholderStyle = false;
+
+ RenderStyle* oldStyle = renderer()->style();
+ if (oldStyle)
+ oldStyle->ref();
+ RenderStyle* _style = new (m_renderArena) RenderStyle();
+ _style->ref();
+ _style->setDisplay(BLOCK);
+ _style->setVisuallyOrdered(visuallyOrdered);
+ // ### make the font stuff _really_ work!!!!
+
+ FontDescription fontDescription;
+ fontDescription.setUsePrinterFont(printing());
+ if (Settings* settings = this->settings()) {
+ fontDescription.setRenderingMode(settings->fontRenderingMode());
+ if (printing() && !settings->shouldPrintBackgrounds())
+ _style->setForceBackgroundsToWhite(true);
+ const AtomicString& stdfont = settings->standardFontFamily();
+ if (!stdfont.isEmpty()) {
+ fontDescription.firstFamily().setFamily(stdfont);
+ fontDescription.firstFamily().appendFamily(0);
+ }
+ fontDescription.setKeywordSize(CSS_VAL_MEDIUM - CSS_VAL_XX_SMALL + 1);
+ m_styleSelector->setFontSize(fontDescription, m_styleSelector->fontSizeForKeyword(CSS_VAL_MEDIUM, inCompatMode(), false));
+ }
+
+ _style->setFontDescription(fontDescription);
+ _style->font().update(m_styleSelector->fontSelector());
+ if (inCompatMode())
+ _style->setHtmlHacks(true); // enable html specific rendering tricks
+
+ StyleChange ch = diff(_style, oldStyle);
+ if (renderer() && ch != NoChange)
+ renderer()->setStyle(_style);
+ if (change != Force)
+ change = ch;
+
+ _style->deref(m_renderArena);
+ if (oldStyle)
+ oldStyle->deref(m_renderArena);
+ }
+
+ for (Node* n = firstChild(); n; n = n->nextSibling())
+ if (change >= Inherit || n->hasChangedChild() || n->changed())
+ n->recalcStyle(change);
+
+ if (changed() && view())
+ view()->layout();
+
+bail_out:
+ setChanged(NoStyleChange);
+ setHasChangedChild(false);
+ setDocumentChanged(false);
+
+ resumePostAttachCallbacks();
+ m_inStyleRecalc = false;
+
+ // If we wanted to call implicitClose() during recalcStyle, do so now that we're finished.
+ if (m_closeAfterStyleRecalc) {
+ m_closeAfterStyleRecalc = false;
+ implicitClose();
+ }
+}
+
+void Document::updateRendering()
+{
+ if (hasChangedChild())
+ recalcStyle(NoChange);
+}
+
+void Document::updateDocumentsRendering()
+{
+ if (!changedDocuments)
+ return;
+
+ while (Document* doc = changedDocuments->take()) {
+ doc->m_docChanged = false;
+ doc->updateRendering();
+ }
+}
+
+void Document::updateLayout()
+{
+ if (Element* oe = ownerElement())
+ oe->document()->updateLayout();
+
+ // FIXME: Dave Hyatt's pretty sure we can remove this because layout calls recalcStyle as needed.
+ updateRendering();
+
+ // Only do a layout if changes have occurred that make it necessary.
+ FrameView* v = view();
+ if (v && renderer() && (v->layoutPending() || renderer()->needsLayout()))
+ v->layout();
+}
+
+// FIXME: This is a bad idea and needs to be removed eventually.
+// Other browsers load stylesheets before they continue parsing the web page.
+// Since we don't, we can run JavaScript code that needs answers before the
+// stylesheets are loaded. Doing a layout ignoring the pending stylesheets
+// lets us get reasonable answers. The long term solution to this problem is
+// to instead suspend JavaScript execution.
+void Document::updateLayoutIgnorePendingStylesheets()
+{
+ bool oldIgnore = m_ignorePendingStylesheets;
+
+ if (!haveStylesheetsLoaded()) {
+ m_ignorePendingStylesheets = true;
+ // FIXME: We are willing to attempt to suppress painting with outdated style info only once. Our assumption is that it would be
+ // dangerous to try to stop it a second time, after page content has already been loaded and displayed
+ // with accurate style information. (Our suppression involves blanking the whole page at the
+ // moment. If it were more refined, we might be able to do something better.)
+ // It's worth noting though that this entire method is a hack, since what we really want to do is
+ // suspend JS instead of doing a layout with inaccurate information.
+ if (body() && !body()->renderer() && m_pendingSheetLayout == NoLayoutWithPendingSheets) {
+ m_pendingSheetLayout = DidLayoutWithPendingSheets;
+ updateStyleSelector();
+ } else if (m_hasNodesWithPlaceholderStyle)
+ // If new nodes have been added or style recalc has been done with style sheets still pending, some nodes
+ // may not have had their real style calculated yet. Normally this gets cleaned when style sheets arrive
+ // but here we need up-to-date style immediatly.
+ recalcStyle(Force);
+ }
+
+ updateLayout();
+
+ m_ignorePendingStylesheets = oldIgnore;
+}
+
+void Document::attach()
+{
+ ASSERT(!attached());
+ ASSERT(!m_inPageCache);
+
+ if (!m_renderArena)
+ m_renderArena = new RenderArena();
+
+ // Create the rendering tree
+ setRenderer(new (m_renderArena) RenderView(this, view()));
+
+ if (!m_styleSelector) {
+ bool matchAuthorAndUserStyles = true;
+ if (Settings* docSettings = settings())
+ matchAuthorAndUserStyles = docSettings->authorAndUserStylesEnabled();
+ m_styleSelector = new CSSStyleSelector(this, userStyleSheet(), m_styleSheets.get(), m_mappedElementSheet.get(), !inCompatMode(), matchAuthorAndUserStyles);
+ m_styleSelector->setEncodedURL(m_url);
+ }
+
+ recalcStyle(Force);
+
+ RenderObject* render = renderer();
+ setRenderer(0);
+
+ ContainerNode::attach();
+
+ setRenderer(render);
+}
+
+void Document::detach()
+{
+ ASSERT(attached());
+ ASSERT(!m_inPageCache);
+
+ RenderObject* render = renderer();
+
+ // indicate destruction mode, i.e. attached() but renderer == 0
+ setRenderer(0);
+
+ // Empty out these lists as a performance optimization, since detaching
+ // all the individual render objects will cause all the RenderImage
+ // objects to remove themselves from the lists.
+ m_imageLoadEventDispatchSoonList.clear();
+ m_imageLoadEventDispatchingList.clear();
+
+ m_hoverNode = 0;
+ m_focusedNode = 0;
+ m_activeNode = 0;
+
+ ContainerNode::detach();
+
+ if (render)
+ render->destroy();
+
+ // FIXME: is this needed or desirable?
+ m_frame = 0;
+
+ if (m_renderArena) {
+ delete m_renderArena;
+ m_renderArena = 0;
+ }
+}
+
+void Document::removeAllEventListenersFromAllNodes()
+{
+ m_windowEventListeners.clear();
+ removeAllDisconnectedNodeEventListeners();
+ for (Node *n = this; n; n = n->traverseNextNode()) {
+ if (!n->isEventTargetNode())
+ continue;
+ EventTargetNodeCast(n)->removeAllEventListeners();
+ }
+}
+
+void Document::registerDisconnectedNodeWithEventListeners(Node* node)
+{
+ m_disconnectedNodesWithEventListeners.add(node);
+}
+
+void Document::unregisterDisconnectedNodeWithEventListeners(Node* node)
+{
+ m_disconnectedNodesWithEventListeners.remove(node);
+}
+
+void Document::removeAllDisconnectedNodeEventListeners()
+{
+ HashSet<Node*>::iterator end = m_disconnectedNodesWithEventListeners.end();
+ for (HashSet<Node*>::iterator i = m_disconnectedNodesWithEventListeners.begin(); i != end; ++i)
+ EventTargetNodeCast(*i)->removeAllEventListeners();
+ m_disconnectedNodesWithEventListeners.clear();
+}
+
+AXObjectCache* Document::axObjectCache() const
+{
+ // The only document that actually has a AXObjectCache is the top-level
+ // document. This is because we need to be able to get from any WebCoreAXObject
+ // to any other WebCoreAXObject on the same page. Using a single cache allows
+ // lookups across nested webareas (i.e. multiple documents).
+
+ if (m_axObjectCache) {
+ // return already known top-level cache
+ if (!ownerElement())
+ return m_axObjectCache;
+
+ // In some pages with frames, the cache is created before the sub-webarea is
+ // inserted into the tree. Here, we catch that case and just toss the old
+ // cache and start over.
+ delete m_axObjectCache;
+ m_axObjectCache = 0;
+ }
+
+ // ask the top-level document for its cache
+ Document* doc = topDocument();
+ if (doc != this)
+ return doc->axObjectCache();
+
+ // this is the top-level document, so install a new cache
+ m_axObjectCache = new AXObjectCache;
+ return m_axObjectCache;
+}
+
+void Document::setVisuallyOrdered()
+{
+ visuallyOrdered = true;
+ if (renderer())
+ renderer()->style()->setVisuallyOrdered(true);
+}
+
+Tokenizer* Document::createTokenizer()
+{
+ // FIXME: this should probably pass the frame instead
+ return new XMLTokenizer(this, view());
+}
+
+void Document::open()
+{
+ // This is work that we should probably do in clear(), but we can't have it
+ // happen when implicitOpen() is called unless we reorganize Frame code.
+ if (Document* parent = parentDocument()) {
+ if (m_url.isEmpty() || m_url == blankURL())
+ setURL(parent->baseURL());
+ if (m_baseURL.isEmpty() || m_baseURL == blankURL())
+ setBaseURL(parent->baseURL());
+ }
+
+ if (m_frame) {
+ if (m_frame->loader()->isLoadingMainResource() || (tokenizer() && tokenizer()->executingScript()))
+ return;
+
+ if (m_frame->loader()->state() == FrameStateProvisional)
+ m_frame->loader()->stopAllLoaders();
+ }
+
+ implicitOpen();
+
+ if (m_frame)
+ m_frame->loader()->didExplicitOpen();
+}
+
+void Document::cancelParsing()
+{
+ if (m_tokenizer) {
+ // We have to clear the tokenizer to avoid possibly triggering
+ // the onload handler when closing as a side effect of a cancel-style
+ // change, such as opening a new document or closing the window while
+ // still parsing
+ delete m_tokenizer;
+ m_tokenizer = 0;
+ close();
+ }
+}
+
+void Document::implicitOpen()
+{
+ cancelParsing();
+
+ clear();
+ m_tokenizer = createTokenizer();
+ setParsing(true);
+}
+
+HTMLElement* Document::body()
+{
+ Node* de = documentElement();
+ if (!de)
+ return 0;
+
+ // try to prefer a FRAMESET element over BODY
+ Node* body = 0;
+ for (Node* i = de->firstChild(); i; i = i->nextSibling()) {
+ if (i->hasTagName(framesetTag))
+ return static_cast<HTMLElement*>(i);
+
+ if (i->hasTagName(bodyTag))
+ body = i;
+ }
+ return static_cast<HTMLElement*>(body);
+}
+
+void Document::setBody(PassRefPtr<HTMLElement> newBody, ExceptionCode& ec)
+{
+ if (!newBody) {
+ ec = HIERARCHY_REQUEST_ERR;
+ return;
+ }
+
+ HTMLElement* b = body();
+ if (!b)
+ documentElement()->appendChild(newBody, ec);
+ else
+ documentElement()->replaceChild(newBody, b, ec);
+}
+
+HTMLHeadElement* Document::head()
+{
+ Node* de = documentElement();
+ if (!de)
+ return 0;
+
+ for (Node* e = de->firstChild(); e; e = e->nextSibling())
+ if (e->hasTagName(headTag))
+ return static_cast<HTMLHeadElement*>(e);
+
+ return 0;
+}
+
+void Document::close()
+{
+ Frame* frame = this->frame();
+ if (frame) {
+ // This code calls implicitClose() if all loading has completed.
+ FrameLoader* frameLoader = frame->loader();
+ frameLoader->endIfNotLoadingMainResource();
+ frameLoader->checkCompleted();
+ } else {
+ // Because we have no frame, we don't know if all loading has completed,
+ // so we just call implicitClose() immediately. FIXME: This might fire
+ // the load event prematurely <http://bugs.webkit.org/show_bug.cgi?id=14568>.
+ implicitClose();
+ }
+}
+
+void Document::implicitClose()
+{
+ // If we're in the middle of recalcStyle, we need to defer the close until the style information is accurate and all elements are re-attached.
+ if (m_inStyleRecalc) {
+ m_closeAfterStyleRecalc = true;
+ return;
+ }
+
+ bool wasLocationChangePending = frame() && frame()->loader()->isScheduledLocationChangePending();
+ bool doload = !parsing() && m_tokenizer && !m_processingLoadEvent && !wasLocationChangePending;
+
+ if (!doload)
+ return;
+
+ m_processingLoadEvent = true;
+
+ m_wellFormed = m_tokenizer && m_tokenizer->wellFormed();
+
+ // We have to clear the tokenizer, in case someone document.write()s from the
+ // onLoad event handler, as in Radar 3206524.
+ delete m_tokenizer;
+ m_tokenizer = 0;
+
+ // Create a body element if we don't already have one. See Radar 3758785.
+ if (!this->body() && isHTMLDocument()) {
+ if (Node* documentElement = this->documentElement()) {
+ ExceptionCode ec = 0;
+ documentElement->appendChild(new HTMLBodyElement(this), ec);
+ ASSERT(!ec);
+ }
+ }
+
+ dispatchImageLoadEventsNow();
+ this->dispatchWindowEvent(loadEvent, false, false);
+ if (Frame* f = frame())
+ f->loader()->handledOnloadEvents();
+#ifdef INSTRUMENT_LAYOUT_SCHEDULING
+ if (!ownerElement())
+ printf("onload fired at %d\n", elapsedTime());
+#endif
+
+ m_processingLoadEvent = false;
+
+ // An event handler may have removed the frame
+ if (!frame())
+ return;
+
+ // Make sure both the initial layout and reflow happen after the onload
+ // fires. This will improve onload scores, and other browsers do it.
+ // If they wanna cheat, we can too. -dwh
+
+ if (frame()->loader()->isScheduledLocationChangePending() && elapsedTime() < cLayoutScheduleThreshold) {
+ // Just bail out. Before or during the onload we were shifted to another page.
+ // The old i-Bench suite does this. When this happens don't bother painting or laying out.
+ view()->unscheduleRelayout();
+ return;
+ }
+
+ frame()->loader()->checkCallImplicitClose();
+
+ // Now do our painting/layout, but only if we aren't in a subframe or if we're in a subframe
+ // that has been sized already. Otherwise, our view size would be incorrect, so doing any
+ // layout/painting now would be pointless.
+ if (!ownerElement() || (ownerElement()->renderer() && !ownerElement()->renderer()->needsLayout())) {
+ updateRendering();
+
+ // Always do a layout after loading if needed.
+ if (view() && renderer() && (!renderer()->firstChild() || renderer()->needsLayout()))
+ view()->layout();
+
+ // Paint immediately after the document is ready. We do this to ensure that any timers set by the
+ // onload don't have a chance to fire before we would have painted. To avoid over-flushing we only
+ // worry about this for the top-level document.
+#if !PLATFORM(MAC)
+ // FIXME: This causes a timing issue with the dispatchDidFinishLoad delegate callback.
+ // See <rdar://problem/5092361>
+ if (view() && !ownerElement())
+ view()->update();
+#endif
+ }
+
+#if PLATFORM(MAC)
+ if (renderer() && AXObjectCache::accessibilityEnabled())
+ axObjectCache()->postNotificationToElement(renderer(), "AXLoadComplete");
+#endif
+
+#if ENABLE(SVG)
+ // FIXME: Officially, time 0 is when the outermost <svg> receives its
+ // SVGLoad event, but we don't implement those yet. This is close enough
+ // for now. In some cases we should have fired earlier.
+ if (svgExtensions())
+ accessSVGExtensions()->startAnimations();
+#endif
+}
+
+void Document::setParsing(bool b)
+{
+ m_bParsing = b;
+ if (!m_bParsing && view())
+ view()->scheduleRelayout();
+
+#ifdef INSTRUMENT_LAYOUT_SCHEDULING
+ if (!ownerElement() && !m_bParsing)
+ printf("Parsing finished at %d\n", elapsedTime());
+#endif
+}
+
+bool Document::shouldScheduleLayout()
+{
+ // We can update layout if:
+ // (a) we actually need a layout
+ // (b) our stylesheets are all loaded
+ // (c) we have a <body>
+ return (renderer() && renderer()->needsLayout() && haveStylesheetsLoaded() &&
+ documentElement() && documentElement()->renderer() &&
+ (!documentElement()->hasTagName(htmlTag) || body()));
+}
+
+int Document::minimumLayoutDelay()
+{
+ if (m_overMinimumLayoutThreshold)
+ return 0;
+
+ int elapsed = elapsedTime();
+ m_overMinimumLayoutThreshold = elapsed > cLayoutScheduleThreshold;
+
+ // We'll want to schedule the timer to fire at the minimum layout threshold.
+ return max(0, cLayoutScheduleThreshold - elapsed);
+}
+
+int Document::elapsedTime() const
+{
+ return static_cast<int>((currentTime() - m_startTime) * 1000);
+}
+
+void Document::write(const String& text)
+{
+#ifdef INSTRUMENT_LAYOUT_SCHEDULING
+ if (!ownerElement())
+ printf("Beginning a document.write at %d\n", elapsedTime());
+#endif
+
+ if (!m_tokenizer) {
+ open();
+ ASSERT(m_tokenizer);
+ if (!m_tokenizer)
+ return;
+ write("<html>");
+ }
+ m_tokenizer->write(text, false);
+
+#ifdef INSTRUMENT_LAYOUT_SCHEDULING
+ if (!ownerElement())
+ printf("Ending a document.write at %d\n", elapsedTime());
+#endif
+}
+
+void Document::writeln(const String& text)
+{
+ write(text);
+ write("\n");
+}
+
+void Document::finishParsing()
+{
+#ifdef INSTRUMENT_LAYOUT_SCHEDULING
+ if (!ownerElement())
+ printf("Received all data at %d\n", elapsedTime());
+#endif
+
+ // Let the tokenizer go through as much data as it can. There will be three possible outcomes after
+ // finish() is called:
+ // (1) All remaining data is parsed, document isn't loaded yet
+ // (2) All remaining data is parsed, document is loaded, tokenizer gets deleted
+ // (3) Data is still remaining to be parsed.
+ if (m_tokenizer)
+ m_tokenizer->finish();
+}
+
+void Document::clear()
+{
+ delete m_tokenizer;
+ m_tokenizer = 0;
+
+ removeChildren();
+
+ m_windowEventListeners.clear();
+}
+
+void Document::setURL(const KURL& url)
+{
+ if (url == m_url)
+ return;
+
+ m_url = url;
+ if (m_styleSelector)
+ m_styleSelector->setEncodedURL(url);
+
+ m_isAllowedToLoadLocalResources = shouldBeAllowedToLoadLocalResources();
+ }
+
+bool Document::shouldBeAllowedToLoadLocalResources() const
+{
+ if (FrameLoader::shouldTreatURLAsLocal(m_url.string()))
+ return true;
+
+ Frame* frame = this->frame();
+ if (!frame)
+ return false;
+
+ DocumentLoader* documentLoader = frame->loader()->documentLoader();
+ if (!documentLoader)
+ return false;
+
+ if (m_url == blankURL() && frame->loader()->opener() && frame->loader()->opener()->document()->isAllowedToLoadLocalResources())
+ return true;
+
+ return documentLoader->substituteData().isValid();
+}
+
+void Document::setBaseURL(const KURL& baseURL)
+{
+ m_baseURL = baseURL;
+ if (m_elemSheet)
+ m_elemSheet->setHref(baseURL.string());
+}
+
+void Document::setCSSStyleSheet(const String &url, const String& charset, const CachedCSSStyleSheet* sheet)
+{
+ m_sheet = new CSSStyleSheet(this, url, charset);
+ m_sheet->parseString(sheet->sheetText());
+
+ updateStyleSelector();
+}
+
+#if FRAME_LOADS_USER_STYLESHEET
+void Document::setUserStyleSheet(const String& sheet)
+{
+ if (m_usersheet != sheet) {
+ m_usersheet = sheet;
+ updateStyleSelector();
+ }
+}
+#endif
+
+String Document::userStyleSheet() const
+{
+#if FRAME_LOADS_USER_STYLESHEET
+ return m_usersheet;
+#else
+ Page* page = this->page();
+ if (!page)
+ return String();
+ return page->userStyleSheet();
+#endif
+}
+
+CSSStyleSheet* Document::elementSheet()
+{
+ if (!m_elemSheet)
+ m_elemSheet = new CSSStyleSheet(this, baseURL().string());
+ return m_elemSheet.get();
+}
+
+CSSStyleSheet* Document::mappedElementSheet()
+{
+ if (!m_mappedElementSheet)
+ m_mappedElementSheet = new CSSStyleSheet(this, baseURL().string());
+ return m_mappedElementSheet.get();
+}
+
+static Node* nextNodeWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent* event)
+{
+ // Search is inclusive of start
+ for (Node* n = start; n; n = n->traverseNextNode())
+ if (n->isKeyboardFocusable(event) && n->tabIndex() == tabIndex)
+ return n;
+
+ return 0;
+}
+
+static Node* previousNodeWithExactTabIndex(Node* start, int tabIndex, KeyboardEvent* event)
+{
+ // Search is inclusive of start
+ for (Node* n = start; n; n = n->traversePreviousNode())
+ if (n->isKeyboardFocusable(event) && n->tabIndex() == tabIndex)
+ return n;
+
+ return 0;
+}
+
+static Node* nextNodeWithGreaterTabIndex(Node* start, int tabIndex, KeyboardEvent* event)
+{
+ // Search is inclusive of start
+ int winningTabIndex = SHRT_MAX + 1;
+ Node* winner = 0;
+ for (Node* n = start; n; n = n->traverseNextNode())
+ if (n->isKeyboardFocusable(event) && n->tabIndex() > tabIndex && n->tabIndex() < winningTabIndex) {
+ winner = n;
+ winningTabIndex = n->tabIndex();
+ }
+
+ return winner;
+}
+
+static Node* previousNodeWithLowerTabIndex(Node* start, int tabIndex, KeyboardEvent* event)
+{
+ // Search is inclusive of start
+ int winningTabIndex = 0;
+ Node* winner = 0;
+ for (Node* n = start; n; n = n->traversePreviousNode())
+ if (n->isKeyboardFocusable(event) && n->tabIndex() < tabIndex && n->tabIndex() > winningTabIndex) {
+ winner = n;
+ winningTabIndex = n->tabIndex();
+ }
+
+ return winner;
+}
+
+Node* Document::nextFocusableNode(Node* start, KeyboardEvent* event)
+{
+ if (start) {
+ // First try to find a node with the same tabindex as start that comes after start in the document.
+ if (Node* winner = nextNodeWithExactTabIndex(start->traverseNextNode(), start->tabIndex(), event))
+ return winner;
+
+ if (start->tabIndex() == 0)
+ // We've reached the last node in the document with a tabindex of 0. This is the end of the tabbing order.
+ return 0;
+ }
+
+ // Look for the first node in the document that:
+ // 1) has the lowest tabindex that is higher than start's tabindex (or 0, if start is null), and
+ // 2) comes first in the document, if there's a tie.
+ if (Node* winner = nextNodeWithGreaterTabIndex(this, start ? start->tabIndex() : 0, event))
+ return winner;
+
+ // There are no nodes with a tabindex greater than start's tabindex,
+ // so find the first node with a tabindex of 0.
+ return nextNodeWithExactTabIndex(this, 0, event);
+}
+
+Node* Document::previousFocusableNode(Node* start, KeyboardEvent* event)
+{
+ Node* last;
+ for (last = this; last->lastChild(); last = last->lastChild())
+ ; // Empty loop.
+
+ // First try to find the last node in the document that comes before start and has the same tabindex as start.
+ // If start is null, find the last node in the document with a tabindex of 0.
+ Node* startingNode;
+ int startingTabIndex;
+ if (start) {
+ startingNode = start->traversePreviousNode();
+ startingTabIndex = start->tabIndex();
+ } else {
+ startingNode = last;
+ startingTabIndex = 0;
+ }
+
+ if (Node* winner = previousNodeWithExactTabIndex(startingNode, startingTabIndex, event))
+ return winner;
+
+ // There are no nodes before start with the same tabindex as start, so look for a node that:
+ // 1) has the highest non-zero tabindex (that is less than start's tabindex), and
+ // 2) comes last in the document, if there's a tie.
+ startingTabIndex = (start && start->tabIndex()) ? start->tabIndex() : SHRT_MAX;
+ return previousNodeWithLowerTabIndex(last, startingTabIndex, event);
+}
+
+int Document::nodeAbsIndex(Node *node)
+{
+ ASSERT(node->document() == this);
+
+ int absIndex = 0;
+ for (Node *n = node; n && n != this; n = n->traversePreviousNode())
+ absIndex++;
+ return absIndex;
+}
+
+Node *Document::nodeWithAbsIndex(int absIndex)
+{
+ Node *n = this;
+ for (int i = 0; n && (i < absIndex); i++) {
+ n = n->traverseNextNode();
+ }
+ return n;
+}
+
+void Document::processHttpEquiv(const String &equiv, const String &content)
+{
+ ASSERT(!equiv.isNull() && !content.isNull());
+
+ Frame *frame = this->frame();
+
+ if (equalIgnoringCase(equiv, "default-style")) {
+ // The preferred style set has been overridden as per section
+ // 14.3.2 of the HTML4.0 specification. We need to update the
+ // sheet used variable and then update our style selector.
+ // For more info, see the test at:
+ // http://www.hixie.ch/tests/evil/css/import/main/preferred.html
+ // -dwh
+ m_selectedStylesheetSet = content;
+ m_preferredStylesheetSet = content;
+ updateStyleSelector();
+ } else if (equalIgnoringCase(equiv, "refresh")) {
+ double delay;
+ String url;
+ if (frame && parseHTTPRefresh(content, true, delay, url)) {
+ if (url.isEmpty())
+ url = frame->loader()->url().string();
+ else
+ url = completeURL(url).string();
+ frame->loader()->scheduleHTTPRedirection(delay, url);
+ }
+ } else if (equalIgnoringCase(equiv, "set-cookie")) {
+ // FIXME: make setCookie work on XML documents too; e.g. in case of <html:meta .....>
+ if (isHTMLDocument())
+ static_cast<HTMLDocument*>(this)->setCookie(content);
+ } else if (equalIgnoringCase(equiv, "content-language"))
+ setContentLanguage(content);
+}
+
+MouseEventWithHitTestResults Document::prepareMouseEvent(const HitTestRequest& request, const IntPoint& documentPoint, const PlatformMouseEvent& event)
+{
+ ASSERT(!renderer() || renderer()->isRenderView());
+
+ if (!renderer())
+ return MouseEventWithHitTestResults(event, HitTestResult(IntPoint()));
+
+ HitTestResult result(documentPoint);
+ renderer()->layer()->hitTest(request, result);
+
+ if (!request.readonly)
+ updateRendering();
+
+ return MouseEventWithHitTestResults(event, result);
+}
+
+// DOM Section 1.1.1
+bool Document::childTypeAllowed(NodeType type)
+{
+ switch (type) {
+ case ATTRIBUTE_NODE:
+ case CDATA_SECTION_NODE:
+ case DOCUMENT_FRAGMENT_NODE:
+ case DOCUMENT_NODE:
+ case ENTITY_NODE:
+ case ENTITY_REFERENCE_NODE:
+ case NOTATION_NODE:
+ case TEXT_NODE:
+ case XPATH_NAMESPACE_NODE:
+ return false;
+ case COMMENT_NODE:
+ case PROCESSING_INSTRUCTION_NODE:
+ return true;
+ case DOCUMENT_TYPE_NODE:
+ case ELEMENT_NODE:
+ // Documents may contain no more than one of each of these.
+ // (One Element and one DocumentType.)
+ for (Node* c = firstChild(); c; c = c->nextSibling())
+ if (c->nodeType() == type)
+ return false;
+ return true;
+ }
+ return false;
+}
+
+bool Document::canReplaceChild(Node* newChild, Node* oldChild)
+{
+ if (!oldChild)
+ // ContainerNode::replaceChild will raise a NOT_FOUND_ERR.
+ return true;
+
+ if (oldChild->nodeType() == newChild->nodeType())
+ return true;
+
+ int numDoctypes = 0;
+ int numElements = 0;
+
+ // First, check how many doctypes and elements we have, not counting
+ // the child we're about to remove.
+ for (Node* c = firstChild(); c; c = c->nextSibling()) {
+ if (c == oldChild)
+ continue;
+
+ switch (c->nodeType()) {
+ case DOCUMENT_TYPE_NODE:
+ numDoctypes++;
+ break;
+ case ELEMENT_NODE:
+ numElements++;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Then, see how many doctypes and elements might be added by the new child.
+ if (newChild->nodeType() == DOCUMENT_FRAGMENT_NODE) {
+ for (Node* c = firstChild(); c; c = c->nextSibling()) {
+ switch (c->nodeType()) {
+ case ATTRIBUTE_NODE:
+ case CDATA_SECTION_NODE:
+ case DOCUMENT_FRAGMENT_NODE:
+ case DOCUMENT_NODE:
+ case ENTITY_NODE:
+ case ENTITY_REFERENCE_NODE:
+ case NOTATION_NODE:
+ case TEXT_NODE:
+ case XPATH_NAMESPACE_NODE:
+ return false;
+ case COMMENT_NODE:
+ case PROCESSING_INSTRUCTION_NODE:
+ break;
+ case DOCUMENT_TYPE_NODE:
+ numDoctypes++;
+ break;
+ case ELEMENT_NODE:
+ numElements++;
+ break;
+ }
+ }
+ } else {
+ switch (newChild->nodeType()) {
+ case ATTRIBUTE_NODE:
+ case CDATA_SECTION_NODE:
+ case DOCUMENT_FRAGMENT_NODE:
+ case DOCUMENT_NODE:
+ case ENTITY_NODE:
+ case ENTITY_REFERENCE_NODE:
+ case NOTATION_NODE:
+ case TEXT_NODE:
+ case XPATH_NAMESPACE_NODE:
+ return false;
+ case COMMENT_NODE:
+ case PROCESSING_INSTRUCTION_NODE:
+ return true;
+ case DOCUMENT_TYPE_NODE:
+ numDoctypes++;
+ break;
+ case ELEMENT_NODE:
+ numElements++;
+ break;
+ }
+ }
+
+ if (numElements > 1 || numDoctypes > 1)
+ return false;
+
+ return true;
+}
+
+PassRefPtr<Node> Document::cloneNode(bool /*deep*/)
+{
+ // Spec says cloning Document nodes is "implementation dependent"
+ // so we do not support it...
+ return 0;
+}
+
+StyleSheetList* Document::styleSheets()
+{
+ return m_styleSheets.get();
+}
+
+String Document::preferredStylesheetSet() const
+{
+ return m_preferredStylesheetSet;
+}
+
+String Document::selectedStylesheetSet() const
+{
+ return m_selectedStylesheetSet;
+}
+
+void Document::setSelectedStylesheetSet(const String& aString)
+{
+ m_selectedStylesheetSet = aString;
+ updateStyleSelector();
+ if (renderer())
+ renderer()->repaint();
+}
+
+// This method is called whenever a top-level stylesheet has finished loading.
+void Document::removePendingSheet()
+{
+ // Make sure we knew this sheet was pending, and that our count isn't out of sync.
+ ASSERT(m_pendingStylesheets > 0);
+
+ m_pendingStylesheets--;
+
+#ifdef INSTRUMENT_LAYOUT_SCHEDULING
+ if (!ownerElement())
+ printf("Stylesheet loaded at time %d. %d stylesheets still remain.\n", elapsedTime(), m_pendingStylesheets);
+#endif
+
+ updateStyleSelector();
+
+ if (!m_pendingStylesheets && m_tokenizer)
+ m_tokenizer->executeScriptsWaitingForStylesheets();
+
+ if (!m_pendingStylesheets && m_gotoAnchorNeededAfterStylesheetsLoad && m_frame)
+ m_frame->loader()->gotoAnchor();
+}
+
+void Document::updateStyleSelector()
+{
+ // Don't bother updating, since we haven't loaded all our style info yet
+ // and haven't calculated the style selector for the first time.
+ if (!m_didCalculateStyleSelector && !haveStylesheetsLoaded())
+ return;
+
+ if (didLayoutWithPendingStylesheets() && m_pendingStylesheets <= 0) {
+ m_pendingSheetLayout = IgnoreLayoutWithPendingSheets;
+ if (renderer())
+ renderer()->repaint();
+ }
+
+#ifdef INSTRUMENT_LAYOUT_SCHEDULING
+ if (!ownerElement())
+ printf("Beginning update of style selector at time %d.\n", elapsedTime());
+#endif
+
+ recalcStyleSelector();
+ recalcStyle(Force);
+
+#ifdef INSTRUMENT_LAYOUT_SCHEDULING
+ if (!ownerElement())
+ printf("Finished update of style selector at time %d\n", elapsedTime());
+#endif
+
+ if (renderer()) {
+ renderer()->setNeedsLayoutAndPrefWidthsRecalc();
+ if (view())
+ view()->scheduleRelayout();
+ }
+}
+
+void Document::recalcStyleSelector()
+{
+ if (!renderer() || !attached())
+ return;
+
+ DeprecatedPtrList<StyleSheet> oldStyleSheets = m_styleSheets->styleSheets;
+ m_styleSheets->styleSheets.clear();
+
+ bool matchAuthorAndUserStyles = true;
+ if (Settings* settings = this->settings())
+ matchAuthorAndUserStyles = settings->authorAndUserStylesEnabled();
+
+ Node* n = matchAuthorAndUserStyles ? this : 0;
+ for ( ; n; n = n->traverseNextNode()) {
+ StyleSheet* sheet = 0;
+
+ if (n->nodeType() == PROCESSING_INSTRUCTION_NODE) {
+ // Processing instruction (XML documents only)
+ ProcessingInstruction* pi = static_cast<ProcessingInstruction*>(n);
+ sheet = pi->sheet();
+#if ENABLE(XSLT)
+ // Don't apply XSL transforms to already transformed documents -- <rdar://problem/4132806>
+ if (pi->isXSL() && !transformSourceDocument()) {
+ // Don't apply XSL transforms until loading is finished.
+ if (!parsing())
+ applyXSLTransform(pi);
+ return;
+ }
+#endif
+ if (!sheet && !pi->localHref().isEmpty()) {
+ // Processing instruction with reference to an element in this document - e.g.
+ // <?xml-stylesheet href="#mystyle">, with the element
+ // <foo id="mystyle">heading { color: red; }</foo> at some location in
+ // the document
+ Element* elem = getElementById(pi->localHref().impl());
+ if (elem) {
+ String sheetText("");
+ for (Node* c = elem->firstChild(); c; c = c->nextSibling()) {
+ if (c->nodeType() == TEXT_NODE || c->nodeType() == CDATA_SECTION_NODE)
+ sheetText += c->nodeValue();
+ }
+
+ CSSStyleSheet* cssSheet = new CSSStyleSheet(this);
+ cssSheet->parseString(sheetText);
+ pi->setCSSStyleSheet(cssSheet);
+ sheet = cssSheet;
+ }
+ }
+ } else if (n->isHTMLElement() && (n->hasTagName(linkTag) || n->hasTagName(styleTag))
+#if ENABLE(SVG)
+ || (n->isSVGElement() && n->hasTagName(SVGNames::styleTag))
+#endif
+ ) {
+ Element* e = static_cast<Element*>(n);
+ AtomicString title = e->getAttribute(titleAttr);
+ bool enabledViaScript = false;
+ if (e->hasLocalName(linkTag)) {
+ // <LINK> element
+ HTMLLinkElement* l = static_cast<HTMLLinkElement*>(n);
+ if (l->isDisabled())
+ continue;
+ enabledViaScript = l->isEnabledViaScript();
+ if (l->isLoading()) {
+ // it is loading but we should still decide which style sheet set to use
+ if (!enabledViaScript && !title.isEmpty() && m_preferredStylesheetSet.isEmpty()) {
+ const AtomicString& rel = e->getAttribute(relAttr);
+ if (!rel.contains("alternate")) {
+ m_preferredStylesheetSet = title;
+ m_selectedStylesheetSet = title;
+ }
+ }
+ continue;
+ }
+ if (!l->sheet())
+ title = nullAtom;
+ }
+
+ // Get the current preferred styleset. This is the
+ // set of sheets that will be enabled.
+#if ENABLE(SVG)
+ if (n->isSVGElement() && n->hasTagName(SVGNames::styleTag))
+ sheet = static_cast<SVGStyleElement*>(n)->sheet();
+ else
+#endif
+ if (e->hasLocalName(linkTag))
+ sheet = static_cast<HTMLLinkElement*>(n)->sheet();
+ else
+ // <STYLE> element
+ sheet = static_cast<HTMLStyleElement*>(n)->sheet();
+
+ // Check to see if this sheet belongs to a styleset
+ // (thus making it PREFERRED or ALTERNATE rather than
+ // PERSISTENT).
+ if (!enabledViaScript && !title.isEmpty()) {
+ // Yes, we have a title.
+ if (m_preferredStylesheetSet.isEmpty()) {
+ // No preferred set has been established. If
+ // we are NOT an alternate sheet, then establish
+ // us as the preferred set. Otherwise, just ignore
+ // this sheet.
+ AtomicString rel = e->getAttribute(relAttr);
+ if (e->hasLocalName(styleTag) || !rel.contains("alternate"))
+ m_preferredStylesheetSet = m_selectedStylesheetSet = title;
+ }
+
+ if (title != m_preferredStylesheetSet)
+ sheet = 0;
+ }
+ }
+
+ if (sheet) {
+ sheet->ref();
+ m_styleSheets->styleSheets.append(sheet);
+ }
+
+ // For HTML documents, stylesheets are not allowed within/after the <BODY> tag. So we
+ // can stop searching here.
+ if (isHTMLDocument() && n->hasTagName(bodyTag))
+ break;
+ }
+
+ // De-reference all the stylesheets in the old list
+ DeprecatedPtrListIterator<StyleSheet> it(oldStyleSheets);
+ for (; it.current(); ++it)
+ it.current()->deref();
+
+ // Create a new style selector
+ delete m_styleSelector;
+ m_styleSelector = new CSSStyleSelector(this, userStyleSheet(), m_styleSheets.get(), m_mappedElementSheet.get(), !inCompatMode(), matchAuthorAndUserStyles);
+ m_styleSelector->setEncodedURL(m_url);
+ m_didCalculateStyleSelector = true;
+}
+
+void Document::setHoverNode(PassRefPtr<Node> newHoverNode)
+{
+ m_hoverNode = newHoverNode;
+}
+
+void Document::setActiveNode(PassRefPtr<Node> newActiveNode)
+{
+ m_activeNode = newActiveNode;
+}
+
+void Document::focusedNodeRemoved()
+{
+ setFocusedNode(0);
+}
+
+void Document::removeFocusedNodeOfSubtree(Node* node, bool amongChildrenOnly)
+{
+ if (!m_focusedNode || this->inPageCache()) // If the document is in the page cache, then we don't need to clear out the focused node.
+ return;
+
+ bool nodeInSubtree = false;
+ if (amongChildrenOnly)
+ nodeInSubtree = m_focusedNode->isDescendantOf(node);
+ else
+ nodeInSubtree = (m_focusedNode == node) || m_focusedNode->isDescendantOf(node);
+
+ if (nodeInSubtree)
+ document()->focusedNodeRemoved();
+}
+
+void Document::hoveredNodeDetached(Node* node)
+{
+ if (!m_hoverNode || (node != m_hoverNode && (!m_hoverNode->isTextNode() || node != m_hoverNode->parent())))
+ return;
+
+ m_hoverNode = node->parent();
+ while (m_hoverNode && !m_hoverNode->renderer())
+ m_hoverNode = m_hoverNode->parent();
+ if (frame())
+ frame()->eventHandler()->scheduleHoverStateUpdate();
+}
+
+void Document::activeChainNodeDetached(Node* node)
+{
+ if (!m_activeNode || (node != m_activeNode && (!m_activeNode->isTextNode() || node != m_activeNode->parent())))
+ return;
+
+ m_activeNode = node->parent();
+ while (m_activeNode && !m_activeNode->renderer())
+ m_activeNode = m_activeNode->parent();
+}
+
+const Vector<DashboardRegionValue>& Document::dashboardRegions() const
+{
+ return m_dashboardRegions;
+}
+
+void Document::setDashboardRegions(const Vector<DashboardRegionValue>& regions)
+{
+ m_dashboardRegions = regions;
+ setDashboardRegionsDirty(false);
+}
+
+bool Document::setFocusedNode(PassRefPtr<Node> newFocusedNode)
+{
+ // Make sure newFocusedNode is actually in this document
+ if (newFocusedNode && (newFocusedNode->document() != this))
+ return true;
+
+ if (m_focusedNode == newFocusedNode)
+ return true;
+
+ if (m_inPageCache)
+ return false;
+
+ bool focusChangeBlocked = false;
+ RefPtr<Node> oldFocusedNode = m_focusedNode;
+ m_focusedNode = 0;
+
+ // Remove focus from the existing focus node (if any)
+ if (oldFocusedNode && !oldFocusedNode->m_inDetach) {
+ if (oldFocusedNode->active())
+ oldFocusedNode->setActive(false);
+
+ oldFocusedNode->setFocus(false);
+
+ // Dispatch a change event for text fields or textareas that have been edited
+ RenderObject *r = static_cast<RenderObject*>(oldFocusedNode.get()->renderer());
+ if (r && (r->isTextArea() || r->isTextField()) && r->isEdited()) {
+ EventTargetNodeCast(oldFocusedNode.get())->dispatchHTMLEvent(changeEvent, true, false);
+ if ((r = static_cast<RenderObject*>(oldFocusedNode.get()->renderer())))
+ r->setEdited(false);
+ }
+
+ // Dispatch the blur event and let the node do any other blur related activities (important for text fields)
+ EventTargetNodeCast(oldFocusedNode.get())->dispatchBlurEvent();
+
+ if (m_focusedNode) {
+ // handler shifted focus
+ focusChangeBlocked = true;
+ newFocusedNode = 0;
+ }
+ EventTargetNodeCast(oldFocusedNode.get())->dispatchUIEvent(DOMFocusOutEvent);
+ if (m_focusedNode) {
+ // handler shifted focus
+ focusChangeBlocked = true;
+ newFocusedNode = 0;
+ }
+ if ((oldFocusedNode.get() == this) && oldFocusedNode->hasOneRef())
+ return true;
+
+ if (oldFocusedNode.get() == oldFocusedNode->rootEditableElement())
+ frame()->editor()->didEndEditing();
+ }
+
+ if (newFocusedNode) {
+ if (newFocusedNode == newFocusedNode->rootEditableElement() && !acceptsEditingFocus(newFocusedNode.get())) {
+ // delegate blocks focus change
+ focusChangeBlocked = true;
+ goto SetFocusedNodeDone;
+ }
+ // Set focus on the new node
+ m_focusedNode = newFocusedNode.get();
+
+ // Dispatch the focus event and let the node do any other focus related activities (important for text fields)
+ EventTargetNodeCast(m_focusedNode.get())->dispatchFocusEvent();
+
+ if (m_focusedNode != newFocusedNode) {
+ // handler shifted focus
+ focusChangeBlocked = true;
+ goto SetFocusedNodeDone;
+ }
+ EventTargetNodeCast(m_focusedNode.get())->dispatchUIEvent(DOMFocusInEvent);
+ if (m_focusedNode != newFocusedNode) {
+ // handler shifted focus
+ focusChangeBlocked = true;
+ goto SetFocusedNodeDone;
+ }
+ m_focusedNode->setFocus();
+
+ if (m_focusedNode.get() == m_focusedNode->rootEditableElement())
+ frame()->editor()->didBeginEditing();
+
+ // eww, I suck. set the qt focus correctly
+ // ### find a better place in the code for this
+ if (view()) {
+ Widget *focusWidget = widgetForNode(m_focusedNode.get());
+ if (focusWidget) {
+ // Make sure a widget has the right size before giving it focus.
+ // Otherwise, we are testing edge cases of the Widget code.
+ // Specifically, in WebCore this does not work well for text fields.
+ updateLayout();
+ // Re-get the widget in case updating the layout changed things.
+ focusWidget = widgetForNode(m_focusedNode.get());
+ }
+ if (focusWidget)
+ focusWidget->setFocus();
+ else
+ view()->setFocus();
+ }
+ }
+
+#if PLATFORM(MAC)
+ if (!focusChangeBlocked && m_focusedNode && AXObjectCache::accessibilityEnabled())
+ axObjectCache()->handleFocusedUIElementChanged();
+#endif
+
+SetFocusedNodeDone:
+ updateRendering();
+ return !focusChangeBlocked;
+ }
+
+void Document::setCSSTarget(Node* n)
+{
+ if (m_cssTarget)
+ m_cssTarget->setChanged();
+ m_cssTarget = n;
+ if (n)
+ n->setChanged();
+}
+
+Node* Document::getCSSTarget() const
+{
+ return m_cssTarget;
+}
+
+void Document::attachNodeIterator(NodeIterator *ni)
+{
+ m_nodeIterators.add(ni);
+}
+
+void Document::detachNodeIterator(NodeIterator *ni)
+{
+ m_nodeIterators.remove(ni);
+}
+
+void Document::notifyBeforeNodeRemoval(Node *n)
+{
+ if (Frame* f = frame()) {
+ f->selectionController()->nodeWillBeRemoved(n);
+ f->dragCaretController()->nodeWillBeRemoved(n);
+ }
+
+ HashSet<NodeIterator*>::const_iterator end = m_nodeIterators.end();
+ for (HashSet<NodeIterator*>::const_iterator it = m_nodeIterators.begin(); it != end; ++it)
+ (*it)->notifyBeforeNodeRemoval(n);
+}
+
+DOMWindow* Document::defaultView() const
+{
+ if (!frame())
+ return 0;
+
+ return frame()->domWindow();
+}
+
+PassRefPtr<Event> Document::createEvent(const String& eventType, ExceptionCode& ec)
+{
+ if (eventType == "UIEvents" || eventType == "UIEvent")
+ return new UIEvent;
+ if (eventType == "MouseEvents" || eventType == "MouseEvent")
+ return new MouseEvent;
+ if (eventType == "MutationEvents" || eventType == "MutationEvent")
+ return new MutationEvent;
+ if (eventType == "KeyboardEvents" || eventType == "KeyboardEvent")
+ return new KeyboardEvent;
+ if (eventType == "HTMLEvents" || eventType == "Event" || eventType == "Events")
+ return new Event;
+ if (eventType == "ProgressEvent")
+ return new ProgressEvent;
+ if (eventType == "TextEvent")
+ return new TextEvent;
+ if (eventType == "OverflowEvent")
+ return new OverflowEvent;
+ if (eventType == "WheelEvent")
+ return new WheelEvent;
+#if ENABLE(SVG)
+ if (eventType == "SVGEvents")
+ return new Event;
+ if (eventType == "SVGZoomEvents")
+ return new SVGZoomEvent;
+#endif
+#if ENABLE(CROSS_DOCUMENT_MESSAGING)
+ if (eventType == "MessageEvent")
+ return new MessageEvent;
+#endif
+ ec = NOT_SUPPORTED_ERR;
+ return 0;
+}
+
+CSSStyleDeclaration *Document::getOverrideStyle(Element */*elt*/, const String &/*pseudoElt*/)
+{
+ return 0; // ###
+}
+
+void Document::handleWindowEvent(Event *evt, bool useCapture)
+{
+ if (m_windowEventListeners.isEmpty())
+ return;
+
+ // if any html event listeners are registered on the window, then dispatch them here
+ RegisteredEventListenerList listenersCopy = m_windowEventListeners;
+ RegisteredEventListenerList::iterator it = listenersCopy.begin();
+
+ for (; it != listenersCopy.end(); ++it)
+ if ((*it)->eventType() == evt->type() && (*it)->useCapture() == useCapture && !(*it)->removed())
+ (*it)->listener()->handleEvent(evt, true);
+}
+
+void Document::setHTMLWindowEventListener(const AtomicString &eventType, PassRefPtr<EventListener> listener)
+{
+ // If we already have it we don't want removeWindowEventListener to delete it
+ removeHTMLWindowEventListener(eventType);
+ if (listener)
+ addWindowEventListener(eventType, listener, false);
+}
+
+EventListener *Document::getHTMLWindowEventListener(const AtomicString &eventType)
+{
+ RegisteredEventListenerList::iterator it = m_windowEventListeners.begin();
+ for (; it != m_windowEventListeners.end(); ++it)
+ if ( (*it)->eventType() == eventType && (*it)->listener()->isHTMLEventListener())
+ return (*it)->listener();
+ return 0;
+}
+
+void Document::removeHTMLWindowEventListener(const AtomicString &eventType)
+{
+ RegisteredEventListenerList::iterator it = m_windowEventListeners.begin();
+ for (; it != m_windowEventListeners.end(); ++it)
+ if ( (*it)->eventType() == eventType && (*it)->listener()->isHTMLEventListener()) {
+ m_windowEventListeners.remove(it);
+ return;
+ }
+}
+
+void Document::addWindowEventListener(const AtomicString &eventType, PassRefPtr<EventListener> listener, bool useCapture)
+{
+ // Remove existing identical listener set with identical arguments.
+ // The DOM 2 spec says that "duplicate instances are discarded" in this case.
+ removeWindowEventListener(eventType, listener.get(), useCapture);
+ m_windowEventListeners.append(new RegisteredEventListener(eventType, listener, useCapture));
+}
+
+void Document::removeWindowEventListener(const AtomicString &eventType, EventListener *listener, bool useCapture)
+{
+ RegisteredEventListener rl(eventType, listener, useCapture);
+ RegisteredEventListenerList::iterator it = m_windowEventListeners.begin();
+ for (; it != m_windowEventListeners.end(); ++it)
+ if (*(*it) == rl) {
+ m_windowEventListeners.remove(it);
+ return;
+ }
+}
+
+bool Document::hasWindowEventListener(const AtomicString &eventType)
+{
+ RegisteredEventListenerList::iterator it = m_windowEventListeners.begin();
+ for (; it != m_windowEventListeners.end(); ++it)
+ if ((*it)->eventType() == eventType) {
+ return true;
+ }
+ return false;
+}
+
+PassRefPtr<EventListener> Document::createHTMLEventListener(const String& functionName, const String& code, Node *node)
+{
+ if (Frame* frm = frame())
+ if (frm->scriptProxy()->isEnabled())
+ return frm->scriptProxy()->createHTMLEventHandler(functionName, code, node);
+ return 0;
+}
+
+void Document::setHTMLWindowEventListener(const AtomicString& eventType, Attribute* attr)
+{
+ setHTMLWindowEventListener(eventType,
+ createHTMLEventListener(attr->localName().string(), attr->value(), 0));
+}
+
+void Document::dispatchImageLoadEventSoon(HTMLImageLoader *image)
+{
+ m_imageLoadEventDispatchSoonList.append(image);
+ if (!m_imageLoadEventTimer.isActive())
+ m_imageLoadEventTimer.startOneShot(0);
+}
+
+void Document::removeImage(HTMLImageLoader* image)
+{
+ // Remove instances of this image from both lists.
+ // Use loops because we allow multiple instances to get into the lists.
+ while (m_imageLoadEventDispatchSoonList.removeRef(image)) { }
+ while (m_imageLoadEventDispatchingList.removeRef(image)) { }
+ if (m_imageLoadEventDispatchSoonList.isEmpty())
+ m_imageLoadEventTimer.stop();
+}
+
+void Document::dispatchImageLoadEventsNow()
+{
+ // need to avoid re-entering this function; if new dispatches are
+ // scheduled before the parent finishes processing the list, they
+ // will set a timer and eventually be processed
+ if (!m_imageLoadEventDispatchingList.isEmpty()) {
+ return;
+ }
+
+ m_imageLoadEventTimer.stop();
+
+ m_imageLoadEventDispatchingList = m_imageLoadEventDispatchSoonList;
+ m_imageLoadEventDispatchSoonList.clear();
+ for (DeprecatedPtrListIterator<HTMLImageLoader> it(m_imageLoadEventDispatchingList); it.current();) {
+ HTMLImageLoader* image = it.current();
+ // Must advance iterator *before* dispatching call.
+ // Otherwise, it might be advanced automatically if dispatching the call had a side effect
+ // of destroying the current HTMLImageLoader, and then we would advance past the *next* item,
+ // missing one altogether.
+ ++it;
+ image->dispatchLoadEvent();
+ }
+ m_imageLoadEventDispatchingList.clear();
+}
+
+void Document::imageLoadEventTimerFired(Timer<Document>*)
+{
+ dispatchImageLoadEventsNow();
+}
+
+Element* Document::ownerElement() const
+{
+ if (!frame())
+ return 0;
+ return frame()->ownerElement();
+}
+
+String Document::cookie() const
+{
+ return cookies(this, url());
+}
+
+void Document::setCookie(const String& value)
+{
+ setCookies(this, url(), policyBaseURL(), value);
+}
+
+String Document::referrer() const
+{
+ if (frame())
+ return frame()->loader()->referrer();
+ return String();
+}
+
+String Document::domain() const
+{
+ return m_securityOrigin->host();
+}
+
+void Document::setDomain(const String& newDomain)
+{
+ // Both NS and IE specify that changing the domain is only allowed when
+ // the new domain is a suffix of the old domain.
+
+ // FIXME: We should add logging indicating why a domain was not allowed.
+
+ // If the new domain is the same as the old domain, still call
+ // m_securityOrigin.setDomainForDOM. This will change the
+ // security check behavior. For example, if a page loaded on port 8000
+ // assigns its current domain using document.domain, the page will
+ // allow other pages loaded on different ports in the same domain that
+ // have also assigned to access this page.
+ if (equalIgnoringCase(domain(), newDomain)) {
+ m_securityOrigin->setDomainFromDOM(newDomain);
+ return;
+ }
+
+ int oldLength = domain().length();
+ int newLength = newDomain.length();
+ // e.g. newDomain = webkit.org (10) and domain() = www.webkit.org (14)
+ if (newLength >= oldLength)
+ return;
+
+ String test = domain();
+ // Check that it's a subdomain, not e.g. "ebkit.org"
+ if (test[oldLength - newLength - 1] != '.')
+ return;
+
+ // Now test is "webkit.org" from domain()
+ // and we check that it's the same thing as newDomain
+ test.remove(0, oldLength - newLength);
+ if (test != newDomain)
+ return;
+
+ m_securityOrigin->setDomainFromDOM(newDomain);
+}
+
+String Document::lastModified() const
+{
+ Frame* f = frame();
+ if (!f)
+ return String();
+ DocumentLoader* loader = f->loader()->documentLoader();
+ if (!loader)
+ return String();
+ return loader->response().httpHeaderField("Last-Modified");
+}
+
+bool Document::isValidName(const String &name)
+{
+ const UChar* s = reinterpret_cast<const UChar*>(name.characters());
+ unsigned length = name.length();
+
+ if (length == 0)
+ return false;
+
+ unsigned i = 0;
+
+ UChar32 c;
+ U16_NEXT(s, i, length, c)
+ if (!isValidNameStart(c))
+ return false;
+
+ while (i < length) {
+ U16_NEXT(s, i, length, c)
+ if (!isValidNamePart(c))
+ return false;
+ }
+
+ return true;
+}
+
+bool Document::parseQualifiedName(const String &qualifiedName, String &prefix, String &localName)
+{
+ unsigned length = qualifiedName.length();
+
+ if (length == 0)
+ return false;
+
+ bool nameStart = true;
+ bool sawColon = false;
+ int colonPos = 0;
+
+ const UChar* s = reinterpret_cast<const UChar*>(qualifiedName.characters());
+ for (unsigned i = 0; i < length;) {
+ UChar32 c;
+ U16_NEXT(s, i, length, c)
+ if (c == ':') {
+ if (sawColon)
+ return false; // multiple colons: not allowed
+ nameStart = true;
+ sawColon = true;
+ colonPos = i - 1;
+ } else if (nameStart) {
+ if (!isValidNameStart(c))
+ return false;
+ nameStart = false;
+ } else {
+ if (!isValidNamePart(c))
+ return false;
+ }
+ }
+
+ if (!sawColon) {
+ prefix = String();
+ localName = qualifiedName;
+ } else {
+ prefix = qualifiedName.substring(0, colonPos);
+ localName = qualifiedName.substring(colonPos + 1);
+ }
+
+ return true;
+}
+
+void Document::addImageMap(HTMLMapElement* imageMap)
+{
+ const AtomicString& name = imageMap->getName();
+ if (!name.impl())
+ return;
+
+ // Add the image map, unless there's already another with that name.
+ // "First map wins" is the rule other browsers seem to implement.
+ m_imageMapsByName.add(name.impl(), imageMap);
+}
+
+void Document::removeImageMap(HTMLMapElement* imageMap)
+{
+ // Remove the image map by name.
+ // But don't remove some other image map that just happens to have the same name.
+ // FIXME: Use a HashCountedSet as we do for IDs to find the first remaining map
+ // once a map has been removed.
+ const AtomicString& name = imageMap->getName();
+ if (!name.impl())
+ return;
+
+ ImageMapsByName::iterator it = m_imageMapsByName.find(name.impl());
+ if (it != m_imageMapsByName.end() && it->second == imageMap)
+ m_imageMapsByName.remove(it);
+}
+
+HTMLMapElement *Document::getImageMap(const String& url) const
+{
+ if (url.isNull())
+ return 0;
+ int hashPos = url.find('#');
+ String name = (hashPos < 0 ? url : url.substring(hashPos + 1)).impl();
+ AtomicString mapName = isHTMLDocument() ? name.lower() : name;
+ return m_imageMapsByName.get(mapName.impl());
+}
+
+void Document::setDecoder(TextResourceDecoder *decoder)
+{
+ m_decoder = decoder;
+}
+
+UChar Document::backslashAsCurrencySymbol() const
+{
+ if (!m_decoder)
+ return '\\';
+ return m_decoder->encoding().backslashAsCurrencySymbol();
+}
+
+KURL Document::completeURL(const String& url)
+{
+ // Always return a null URL when passed a null string.
+ // FIXME: Should we change the KURL constructor to have this behavior?
+ if (url.isNull())
+ return KURL();
+ KURL base = m_baseURL;
+ if (base.isEmpty())
+ base = m_url;
+ if (!m_decoder)
+ return KURL(base, url);
+ return KURL(base, url, m_decoder->encoding());
+}
+
+bool Document::inPageCache()
+{
+ return m_inPageCache;
+}
+
+void Document::setInPageCache(bool flag)
+{
+ if (m_inPageCache == flag)
+ return;
+
+ m_inPageCache = flag;
+ if (flag) {
+ ASSERT(m_savedRenderer == 0);
+ m_savedRenderer = renderer();
+ if (FrameView* v = view())
+ v->resetScrollbars();
+ } else {
+ ASSERT(renderer() == 0 || renderer() == m_savedRenderer);
+ ASSERT(m_renderArena);
+ setRenderer(m_savedRenderer);
+ m_savedRenderer = 0;
+ }
+}
+
+void Document::willSaveToCache()
+{
+ HashSet<Element*>::iterator end = m_pageCacheCallbackElements.end();
+ for (HashSet<Element*>::iterator i = m_pageCacheCallbackElements.begin(); i != end; ++i)
+ (*i)->willSaveToCache();
+}
+
+void Document::didRestoreFromCache()
+{
+ HashSet<Element*>::iterator end = m_pageCacheCallbackElements.end();
+ for (HashSet<Element*>::iterator i = m_pageCacheCallbackElements.begin(); i != end; ++i)
+ (*i)->didRestoreFromCache();
+}
+
+void Document::registerForCacheCallbacks(Element* e)
+{
+ m_pageCacheCallbackElements.add(e);
+}
+
+void Document::unregisterForCacheCallbacks(Element* e)
+{
+ m_pageCacheCallbackElements.remove(e);
+}
+
+void Document::setShouldCreateRenderers(bool f)
+{
+ m_createRenderers = f;
+}
+
+bool Document::shouldCreateRenderers()
+{
+ return m_createRenderers;
+}
+
+String Document::toString() const
+{
+ String result;
+
+ for (Node *child = firstChild(); child != NULL; child = child->nextSibling()) {
+ result += child->toString();
+ }
+
+ return result;
+}
+
+// Support for Javascript execCommand, and related methods
+
+static Editor::Command command(Document* document, const String& commandName, bool userInterface = false)
+{
+ Frame* frame = document->frame();
+ if (!frame || frame->document() != document)
+ return Editor::Command();
+ return frame->editor()->command(commandName,
+ userInterface ? CommandFromDOMWithUserInterface : CommandFromDOM);
+}
+
+bool Document::execCommand(const String& commandName, bool userInterface, const String& value)
+{
+ return command(this, commandName, userInterface).execute(value);
+}
+
+bool Document::queryCommandEnabled(const String& commandName)
+{
+ return command(this, commandName).isEnabled();
+}
+
+bool Document::queryCommandIndeterm(const String& commandName)
+{
+ return command(this, commandName).state() == MixedTriState;
+}
+
+bool Document::queryCommandState(const String& commandName)
+{
+ return command(this, commandName).state() != FalseTriState;
+}
+
+bool Document::queryCommandSupported(const String& commandName)
+{
+ return command(this, commandName).isSupported();
+}
+
+String Document::queryCommandValue(const String& commandName)
+{
+ return command(this, commandName).value();
+}
+
+static IntRect placeholderRectForMarker()
+{
+ return IntRect(-1, -1, -1, -1);
+}
+
+void Document::addMarker(Range *range, DocumentMarker::MarkerType type, String description)
+{
+ // Use a TextIterator to visit the potentially multiple nodes the range covers.
+ for (TextIterator markedText(range); !markedText.atEnd(); markedText.advance()) {
+ RefPtr<Range> textPiece = markedText.range();
+ int exception = 0;
+ DocumentMarker marker = {type, textPiece->startOffset(exception), textPiece->endOffset(exception), description};
+ addMarker(textPiece->startContainer(exception), marker);
+ }
+}
+
+void Document::removeMarkers(Range* range, DocumentMarker::MarkerType markerType)
+{
+ if (m_markers.isEmpty())
+ return;
+
+ ExceptionCode ec = 0;
+ Node* startContainer = range->startContainer(ec);
+ Node* endContainer = range->endContainer(ec);
+
+ Node* pastEndNode = range->pastEndNode();
+ for (Node* node = range->startNode(); node != pastEndNode; node = node->traverseNextNode()) {
+ int startOffset = node == startContainer ? range->startOffset(ec) : 0;
+ int endOffset = node == endContainer ? range->endOffset(ec) : INT_MAX;
+ int length = endOffset - startOffset;
+ removeMarkers(node, startOffset, length, markerType);
+ }
+}
+
+// Markers are stored in order sorted by their location.
+// They do not overlap each other, as currently required by the drawing code in RenderText.cpp.
+
+void Document::addMarker(Node *node, DocumentMarker newMarker)
+{
+ ASSERT(newMarker.endOffset >= newMarker.startOffset);
+ if (newMarker.endOffset == newMarker.startOffset)
+ return;
+
+ MarkerMapVectorPair* vectorPair = m_markers.get(node);
+
+ if (!vectorPair) {
+ vectorPair = new MarkerMapVectorPair;
+ vectorPair->first.append(newMarker);
+ vectorPair->second.append(placeholderRectForMarker());
+ m_markers.set(node, vectorPair);
+ } else {
+ Vector<DocumentMarker>& markers = vectorPair->first;
+ Vector<IntRect>& rects = vectorPair->second;
+ ASSERT(markers.size() == rects.size());
+ size_t i;
+ for (i = 0; i != markers.size();) {
+ DocumentMarker marker = markers[i];
+
+ if (newMarker.endOffset < marker.startOffset+1) {
+ // This is the first marker that is completely after newMarker, and disjoint from it.
+ // We found our insertion point.
+ break;
+ } else if (newMarker.startOffset > marker.endOffset) {
+ // maker is before newMarker, and disjoint from it. Keep scanning.
+ i++;
+ } else if (newMarker == marker) {
+ // already have this one, NOP
+ return;
+ } else {
+ // marker and newMarker intersect or touch - merge them into newMarker
+ newMarker.startOffset = min(newMarker.startOffset, marker.startOffset);
+ newMarker.endOffset = max(newMarker.endOffset, marker.endOffset);
+ // remove old one, we'll add newMarker later
+ markers.remove(i);
+ rects.remove(i);
+ // it points to the next marker to consider
+ }
+ }
+ // at this point i points to the node before which we want to insert
+ markers.insert(i, newMarker);
+ rects.insert(i, placeholderRectForMarker());
+ }
+
+ // repaint the affected node
+ if (node->renderer())
+ node->renderer()->repaint();
+}
+
+// copies markers from srcNode to dstNode, applying the specified shift delta to the copies. The shift is
+// useful if, e.g., the caller has created the dstNode from a non-prefix substring of the srcNode.
+void Document::copyMarkers(Node *srcNode, unsigned startOffset, int length, Node *dstNode, int delta, DocumentMarker::MarkerType markerType)
+{
+ if (length <= 0)
+ return;
+
+ MarkerMapVectorPair* vectorPair = m_markers.get(srcNode);
+ if (!vectorPair)
+ return;
+
+ ASSERT(vectorPair->first.size() == vectorPair->second.size());
+
+ bool docDirty = false;
+ unsigned endOffset = startOffset + length - 1;
+ Vector<DocumentMarker>& markers = vectorPair->first;
+ for (size_t i = 0; i != markers.size(); ++i) {
+ DocumentMarker marker = markers[i];
+
+ // stop if we are now past the specified range
+ if (marker.startOffset > endOffset)
+ break;
+
+ // skip marker that is before the specified range or is the wrong type
+ if (marker.endOffset < startOffset || (marker.type != markerType && markerType != DocumentMarker::AllMarkers))
+ continue;
+
+ // pin the marker to the specified range and apply the shift delta
+ docDirty = true;
+ if (marker.startOffset < startOffset)
+ marker.startOffset = startOffset;
+ if (marker.endOffset > endOffset)
+ marker.endOffset = endOffset;
+ marker.startOffset += delta;
+ marker.endOffset += delta;
+
+ addMarker(dstNode, marker);
+ }
+
+ // repaint the affected node
+ if (docDirty && dstNode->renderer())
+ dstNode->renderer()->repaint();
+}
+
+void Document::removeMarkers(Node* node, unsigned startOffset, int length, DocumentMarker::MarkerType markerType)
+{
+ if (length <= 0)
+ return;
+
+ MarkerMapVectorPair* vectorPair = m_markers.get(node);
+ if (!vectorPair)
+ return;
+
+ Vector<DocumentMarker>& markers = vectorPair->first;
+ Vector<IntRect>& rects = vectorPair->second;
+ ASSERT(markers.size() == rects.size());
+ bool docDirty = false;
+ unsigned endOffset = startOffset + length;
+ for (size_t i = 0; i < markers.size();) {
+ DocumentMarker marker = markers[i];
+
+ // markers are returned in order, so stop if we are now past the specified range
+ if (marker.startOffset >= endOffset)
+ break;
+
+ // skip marker that is wrong type or before target
+ if (marker.endOffset < startOffset || (marker.type != markerType && markerType != DocumentMarker::AllMarkers)) {
+ i++;
+ continue;
+ }
+
+ // at this point we know that marker and target intersect in some way
+ docDirty = true;
+
+ // pitch the old marker and any associated rect
+ markers.remove(i);
+ rects.remove(i);
+
+ // add either of the resulting slices that are left after removing target
+ if (startOffset > marker.startOffset) {
+ DocumentMarker newLeft = marker;
+ newLeft.endOffset = startOffset;
+ markers.insert(i, newLeft);
+ rects.insert(i, placeholderRectForMarker());
+ // i now points to the newly-inserted node, but we want to skip that one
+ i++;
+ }
+ if (marker.endOffset > endOffset) {
+ DocumentMarker newRight = marker;
+ newRight.startOffset = endOffset;
+ markers.insert(i, newRight);
+ rects.insert(i, placeholderRectForMarker());
+ // i now points to the newly-inserted node, but we want to skip that one
+ i++;
+ }
+ }
+
+ if (markers.isEmpty()) {
+ ASSERT(rects.isEmpty());
+ m_markers.remove(node);
+ delete vectorPair;
+ }
+
+ // repaint the affected node
+ if (docDirty && node->renderer())
+ node->renderer()->repaint();
+}
+
+DocumentMarker* Document::markerContainingPoint(const IntPoint& point, DocumentMarker::MarkerType markerType)
+{
+ // outer loop: process each node that contains any markers
+ MarkerMap::iterator end = m_markers.end();
+ for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) {
+ // inner loop; process each marker in this node
+ MarkerMapVectorPair* vectorPair = nodeIterator->second;
+ Vector<DocumentMarker>& markers = vectorPair->first;
+ Vector<IntRect>& rects = vectorPair->second;
+ ASSERT(markers.size() == rects.size());
+ unsigned markerCount = markers.size();
+ for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
+ DocumentMarker& marker = markers[markerIndex];
+
+ // skip marker that is wrong type
+ if (marker.type != markerType && markerType != DocumentMarker::AllMarkers)
+ continue;
+
+ IntRect& r = rects[markerIndex];
+
+ // skip placeholder rects
+ if (r == placeholderRectForMarker())
+ continue;
+
+ if (r.contains(point))
+ return &marker;
+ }
+ }
+
+ return 0;
+}
+
+Vector<DocumentMarker> Document::markersForNode(Node* node)
+{
+ MarkerMapVectorPair* vectorPair = m_markers.get(node);
+ if (vectorPair)
+ return vectorPair->first;
+ return Vector<DocumentMarker>();
+}
+
+Vector<IntRect> Document::renderedRectsForMarkers(DocumentMarker::MarkerType markerType)
+{
+ Vector<IntRect> result;
+
+ // outer loop: process each node
+ MarkerMap::iterator end = m_markers.end();
+ for (MarkerMap::iterator nodeIterator = m_markers.begin(); nodeIterator != end; ++nodeIterator) {
+ // inner loop; process each marker in this node
+ MarkerMapVectorPair* vectorPair = nodeIterator->second;
+ Vector<DocumentMarker>& markers = vectorPair->first;
+ Vector<IntRect>& rects = vectorPair->second;
+ ASSERT(markers.size() == rects.size());
+ unsigned markerCount = markers.size();
+ for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
+ DocumentMarker marker = markers[markerIndex];
+
+ // skip marker that is wrong type
+ if (marker.type != markerType && markerType != DocumentMarker::AllMarkers)
+ continue;
+
+ IntRect r = rects[markerIndex];
+ // skip placeholder rects
+ if (r == placeholderRectForMarker())
+ continue;
+
+ result.append(r);
+ }
+ }
+
+ return result;
+}
+
+void Document::removeMarkers(Node* node)
+{
+ MarkerMap::iterator i = m_markers.find(node);
+ if (i != m_markers.end()) {
+ delete i->second;
+ m_markers.remove(i);
+ if (RenderObject* renderer = node->renderer())
+ renderer->repaint();
+ }
+}
+
+void Document::removeMarkers(DocumentMarker::MarkerType markerType)
+{
+ // outer loop: process each markered node in the document
+ MarkerMap markerMapCopy = m_markers;
+ MarkerMap::iterator end = markerMapCopy.end();
+ for (MarkerMap::iterator i = markerMapCopy.begin(); i != end; ++i) {
+ Node* node = i->first.get();
+ bool nodeNeedsRepaint = false;
+
+ // inner loop: process each marker in the current node
+ MarkerMapVectorPair* vectorPair = i->second;
+ Vector<DocumentMarker>& markers = vectorPair->first;
+ Vector<IntRect>& rects = vectorPair->second;
+ ASSERT(markers.size() == rects.size());
+ for (size_t i = 0; i != markers.size();) {
+ DocumentMarker marker = markers[i];
+
+ // skip nodes that are not of the specified type
+ if (marker.type != markerType && markerType != DocumentMarker::AllMarkers) {
+ ++i;
+ continue;
+ }
+
+ // pitch the old marker
+ markers.remove(i);
+ rects.remove(i);
+ nodeNeedsRepaint = true;
+ // markerIterator now points to the next node
+ }
+
+ // Redraw the node if it changed. Do this before the node is removed from m_markers, since
+ // m_markers might contain the last reference to the node.
+ if (nodeNeedsRepaint) {
+ RenderObject* renderer = node->renderer();
+ if (renderer)
+ renderer->repaint();
+ }
+
+ // delete the node's list if it is now empty
+ if (markers.isEmpty()) {
+ ASSERT(rects.isEmpty());
+ m_markers.remove(node);
+ delete vectorPair;
+ }
+ }
+}
+
+void Document::repaintMarkers(DocumentMarker::MarkerType markerType)
+{
+ // outer loop: process each markered node in the document
+ MarkerMap::iterator end = m_markers.end();
+ for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) {
+ Node* node = i->first.get();
+
+ // inner loop: process each marker in the current node
+ MarkerMapVectorPair* vectorPair = i->second;
+ Vector<DocumentMarker>& markers = vectorPair->first;
+ bool nodeNeedsRepaint = false;
+ for (size_t i = 0; i != markers.size(); ++i) {
+ DocumentMarker marker = markers[i];
+
+ // skip nodes that are not of the specified type
+ if (marker.type == markerType || markerType == DocumentMarker::AllMarkers) {
+ nodeNeedsRepaint = true;
+ break;
+ }
+ }
+
+ if (!nodeNeedsRepaint)
+ continue;
+
+ // cause the node to be redrawn
+ if (RenderObject* renderer = node->renderer())
+ renderer->repaint();
+ }
+}
+
+void Document::setRenderedRectForMarker(Node* node, DocumentMarker marker, const IntRect& r)
+{
+ MarkerMapVectorPair* vectorPair = m_markers.get(node);
+ if (!vectorPair) {
+ ASSERT_NOT_REACHED(); // shouldn't be trying to set the rect for a marker we don't already know about
+ return;
+ }
+
+ Vector<DocumentMarker>& markers = vectorPair->first;
+ ASSERT(markers.size() == vectorPair->second.size());
+ unsigned markerCount = markers.size();
+ for (unsigned markerIndex = 0; markerIndex < markerCount; ++markerIndex) {
+ DocumentMarker m = markers[markerIndex];
+ if (m == marker) {
+ vectorPair->second[markerIndex] = r;
+ return;
+ }
+ }
+
+ ASSERT_NOT_REACHED(); // shouldn't be trying to set the rect for a marker we don't already know about
+}
+
+void Document::invalidateRenderedRectsForMarkersInRect(const IntRect& r)
+{
+ // outer loop: process each markered node in the document
+ MarkerMap::iterator end = m_markers.end();
+ for (MarkerMap::iterator i = m_markers.begin(); i != end; ++i) {
+
+ // inner loop: process each rect in the current node
+ MarkerMapVectorPair* vectorPair = i->second;
+ Vector<IntRect>& rects = vectorPair->second;
+
+ unsigned rectCount = rects.size();
+ for (unsigned rectIndex = 0; rectIndex < rectCount; ++rectIndex)
+ if (rects[rectIndex].intersects(r))
+ rects[rectIndex] = placeholderRectForMarker();
+ }
+}
+
+void Document::shiftMarkers(Node *node, unsigned startOffset, int delta, DocumentMarker::MarkerType markerType)
+{
+ MarkerMapVectorPair* vectorPair = m_markers.get(node);
+ if (!vectorPair)
+ return;
+
+ Vector<DocumentMarker>& markers = vectorPair->first;
+ Vector<IntRect>& rects = vectorPair->second;
+ ASSERT(markers.size() == rects.size());
+
+ bool docDirty = false;
+ for (size_t i = 0; i != markers.size(); ++i) {
+ DocumentMarker &marker = markers[i];
+ if (marker.startOffset >= startOffset && (markerType == DocumentMarker::AllMarkers || marker.type == markerType)) {
+ ASSERT((int)marker.startOffset + delta >= 0);
+ marker.startOffset += delta;
+ marker.endOffset += delta;
+ docDirty = true;
+
+ // Marker moved, so previously-computed rendered rectangle is now invalid
+ rects[i] = placeholderRectForMarker();
+ }
+ }
+
+ // repaint the affected node
+ if (docDirty && node->renderer())
+ node->renderer()->repaint();
+}
+
+#if ENABLE(XSLT)
+
+void Document::applyXSLTransform(ProcessingInstruction* pi)
+{
+ RefPtr<XSLTProcessor> processor = XSLTProcessor::create();
+ processor->setXSLStylesheet(static_cast<XSLStyleSheet*>(pi->sheet()));
+
+ String resultMIMEType;
+ String newSource;
+ String resultEncoding;
+ if (!processor->transformToString(this, resultMIMEType, newSource, resultEncoding))
+ return;
+ // FIXME: If the transform failed we should probably report an error (like Mozilla does).
+ processor->createDocumentFromSource(newSource, resultEncoding, resultMIMEType, this, frame());
+}
+
+void Document::setTransformSource(void* doc)
+{
+ if (doc == m_transformSource)
+ return;
+
+ xmlFreeDoc((xmlDocPtr)m_transformSource);
+ m_transformSource = doc;
+}
+
+#endif
+
+void Document::setDesignMode(InheritedBool value)
+{
+ m_designMode = value;
+}
+
+Document::InheritedBool Document::getDesignMode() const
+{
+ return m_designMode;
+}
+
+bool Document::inDesignMode() const
+{
+ for (const Document* d = this; d; d = d->parentDocument()) {
+ if (d->m_designMode != inherit)
+ return d->m_designMode;
+ }
+ return false;
+}
+
+Document *Document::parentDocument() const
+{
+ Frame *childPart = frame();
+ if (!childPart)
+ return 0;
+ Frame *parent = childPart->tree()->parent();
+ if (!parent)
+ return 0;
+ return parent->document();
+}
+
+Document *Document::topDocument() const
+{
+ Document *doc = const_cast<Document *>(this);
+ Element *element;
+ while ((element = doc->ownerElement()))
+ doc = element->document();
+
+ return doc;
+}
+
+PassRefPtr<Attr> Document::createAttributeNS(const String &namespaceURI, const String &qualifiedName, ExceptionCode& ec)
+{
+ if (qualifiedName.isNull()) {
+ ec = NAMESPACE_ERR;
+ return 0;
+ }
+
+ String localName = qualifiedName;
+ String prefix;
+ int colonpos;
+ if ((colonpos = qualifiedName.find(':')) >= 0) {
+ prefix = qualifiedName.substring(0, colonpos);
+ localName = qualifiedName.substring(colonpos + 1);
+ }
+
+ if (!isValidName(localName)) {
+ ec = INVALID_CHARACTER_ERR;
+ return 0;
+ }
+
+ // FIXME: Assume this is a mapped attribute, since createAttribute isn't namespace-aware. There's no harm to XML
+ // documents if we're wrong.
+ return new Attr(0, this, new MappedAttribute(QualifiedName(prefix, localName, namespaceURI), StringImpl::empty()));
+}
+
+#if ENABLE(SVG)
+const SVGDocumentExtensions* Document::svgExtensions()
+{
+ return m_svgExtensions;
+}
+
+SVGDocumentExtensions* Document::accessSVGExtensions()
+{
+ if (!m_svgExtensions)
+ m_svgExtensions = new SVGDocumentExtensions(this);
+ return m_svgExtensions;
+}
+#endif
+
+PassRefPtr<HTMLCollection> Document::images()
+{
+ return new HTMLCollection(this, HTMLCollection::DocImages);
+}
+
+PassRefPtr<HTMLCollection> Document::applets()
+{
+ return new HTMLCollection(this, HTMLCollection::DocApplets);
+}
+
+PassRefPtr<HTMLCollection> Document::embeds()
+{
+ return new HTMLCollection(this, HTMLCollection::DocEmbeds);
+}
+
+PassRefPtr<HTMLCollection> Document::plugins()
+{
+ // This is an alias for embeds() required for the JS DOM bindings.
+ return new HTMLCollection(this, HTMLCollection::DocEmbeds);
+}
+
+PassRefPtr<HTMLCollection> Document::objects()
+{
+ return new HTMLCollection(this, HTMLCollection::DocObjects);
+}
+
+PassRefPtr<HTMLCollection> Document::scripts()
+{
+ return new HTMLCollection(this, HTMLCollection::DocScripts);
+}
+
+PassRefPtr<HTMLCollection> Document::links()
+{
+ return new HTMLCollection(this, HTMLCollection::DocLinks);
+}
+
+PassRefPtr<HTMLCollection> Document::forms()
+{
+ return new HTMLCollection(this, HTMLCollection::DocForms);
+}
+
+PassRefPtr<HTMLCollection> Document::anchors()
+{
+ return new HTMLCollection(this, HTMLCollection::DocAnchors);
+}
+
+PassRefPtr<HTMLCollection> Document::all()
+{
+ return new HTMLCollection(this, HTMLCollection::DocAll);
+}
+
+PassRefPtr<HTMLCollection> Document::windowNamedItems(const String &name)
+{
+ return new HTMLNameCollection(this, HTMLCollection::WindowNamedItems, name);
+}
+
+PassRefPtr<HTMLCollection> Document::documentNamedItems(const String &name)
+{
+ return new HTMLNameCollection(this, HTMLCollection::DocumentNamedItems, name);
+}
+
+HTMLCollection::CollectionInfo* Document::nameCollectionInfo(HTMLCollection::Type type, const AtomicString& name)
+{
+ ASSERT(type >= HTMLCollection::FirstNamedDocumentCachedType);
+ unsigned index = type - HTMLCollection::FirstNamedDocumentCachedType;
+ ASSERT(index < HTMLCollection::NumNamedDocumentCachedTypes);
+
+ NamedCollectionMap& map = m_nameCollectionInfo[index];
+ NamedCollectionMap::iterator iter = map.find(name.impl());
+ if (iter == map.end())
+ iter = map.add(name.impl(), new HTMLCollection::CollectionInfo).first;
+ return iter->second;
+}
+
+void Document::finishedParsing()
+{
+ setParsing(false);
+
+ ExceptionCode ec = 0;
+ dispatchEvent(new Event(DOMContentLoadedEvent, true, false), ec);
+
+ if (Frame* f = frame())
+ f->loader()->finishedParsing();
+}
+
+Vector<String> Document::formElementsState() const
+{
+ Vector<String> stateVector;
+ stateVector.reserveCapacity(m_formElementsWithState.size() * 3);
+ typedef ListHashSet<HTMLFormControlElementWithState*>::const_iterator Iterator;
+ Iterator end = m_formElementsWithState.end();
+ for (Iterator it = m_formElementsWithState.begin(); it != end; ++it) {
+ HTMLFormControlElementWithState* e = *it;
+ String value;
+ if (e->saveState(value)) {
+ stateVector.append(e->name().string());
+ stateVector.append(e->type().string());
+ stateVector.append(value);
+ }
+ }
+ return stateVector;
+}
+
+#if ENABLE(XPATH)
+
+PassRefPtr<XPathExpression> Document::createExpression(const String& expression,
+ XPathNSResolver* resolver,
+ ExceptionCode& ec)
+{
+ if (!m_xpathEvaluator)
+ m_xpathEvaluator = XPathEvaluator::create();
+ return m_xpathEvaluator->createExpression(expression, resolver, ec);
+}
+
+PassRefPtr<XPathNSResolver> Document::createNSResolver(Node* nodeResolver)
+{
+ if (!m_xpathEvaluator)
+ m_xpathEvaluator = XPathEvaluator::create();
+ return m_xpathEvaluator->createNSResolver(nodeResolver);
+}
+
+PassRefPtr<XPathResult> Document::evaluate(const String& expression,
+ Node* contextNode,
+ XPathNSResolver* resolver,
+ unsigned short type,
+ XPathResult* result,
+ ExceptionCode& ec)
+{
+ if (!m_xpathEvaluator)
+ m_xpathEvaluator = XPathEvaluator::create();
+ return m_xpathEvaluator->evaluate(expression, contextNode, resolver, type, result, ec);
+}
+
+#endif // ENABLE(XPATH)
+
+void Document::setStateForNewFormElements(const Vector<String>& stateVector)
+{
+ // Walk the state vector backwards so that the value to use for each
+ // name/type pair first is the one at the end of each individual vector
+ // in the FormElementStateMap. We're using them like stacks.
+ typedef FormElementStateMap::iterator Iterator;
+ m_formElementsWithState.clear();
+ for (size_t i = stateVector.size() / 3 * 3; i; i -= 3) {
+ AtomicString a = stateVector[i - 3];
+ AtomicString b = stateVector[i - 2];
+ const String& c = stateVector[i - 1];
+ FormElementKey key(a.impl(), b.impl());
+ Iterator it = m_stateForNewFormElements.find(key);
+ if (it != m_stateForNewFormElements.end())
+ it->second.append(c);
+ else {
+ Vector<String> v(1);
+ v[0] = c;
+ m_stateForNewFormElements.set(key, v);
+ }
+ }
+}
+
+bool Document::hasStateForNewFormElements() const
+{
+ return !m_stateForNewFormElements.isEmpty();
+}
+
+bool Document::takeStateForFormElement(AtomicStringImpl* name, AtomicStringImpl* type, String& state)
+{
+ typedef FormElementStateMap::iterator Iterator;
+ Iterator it = m_stateForNewFormElements.find(FormElementKey(name, type));
+ if (it == m_stateForNewFormElements.end())
+ return false;
+ ASSERT(it->second.size());
+ state = it->second.last();
+ if (it->second.size() > 1)
+ it->second.removeLast();
+ else
+ m_stateForNewFormElements.remove(it);
+ return true;
+}
+
+FormElementKey::FormElementKey(AtomicStringImpl* name, AtomicStringImpl* type)
+ : m_name(name), m_type(type)
+{
+ ref();
+}
+
+FormElementKey::~FormElementKey()
+{
+ deref();
+}
+
+FormElementKey::FormElementKey(const FormElementKey& other)
+ : m_name(other.name()), m_type(other.type())
+{
+ ref();
+}
+
+FormElementKey& FormElementKey::operator=(const FormElementKey& other)
+{
+ other.ref();
+ deref();
+ m_name = other.name();
+ m_type = other.type();
+ return *this;
+}
+
+void FormElementKey::ref() const
+{
+ if (name() && name() != HashTraits<AtomicStringImpl*>::deletedValue())
+ name()->ref();
+ if (type())
+ type()->ref();
+}
+
+void FormElementKey::deref() const
+{
+ if (name() && name() != HashTraits<AtomicStringImpl*>::deletedValue())
+ name()->deref();
+ if (type())
+ type()->deref();
+}
+
+unsigned FormElementKeyHash::hash(const FormElementKey& k)
+{
+ ASSERT(sizeof(k) % (sizeof(uint16_t) * 2) == 0);
+
+ unsigned l = sizeof(k) / (sizeof(uint16_t) * 2);
+ const uint16_t* s = reinterpret_cast<const uint16_t*>(&k);
+ uint32_t hash = PHI;
+
+ // Main loop
+ for (; l > 0; l--) {
+ hash += s[0];
+ uint32_t tmp = (s[1] << 11) ^ hash;
+ hash = (hash << 16) ^ tmp;
+ s += 2;
+ hash += hash >> 11;
+ }
+
+ // Force "avalanching" of final 127 bits
+ hash ^= hash << 3;
+ hash += hash >> 5;
+ hash ^= hash << 2;
+ hash += hash >> 15;
+ hash ^= hash << 10;
+
+ // this avoids ever returning a hash code of 0, since that is used to
+ // signal "hash not computed yet", using a value that is likely to be
+ // effectively the same as 0 when the low bits are masked
+ if (hash == 0)
+ hash = 0x80000000;
+
+ return hash;
+}
+
+FormElementKey FormElementKeyHashTraits::deletedValue()
+{
+ return HashTraits<AtomicStringImpl*>::deletedValue();
+}
+
+
+String Document::iconURL()
+{
+ return m_iconURL;
+}
+
+void Document::setIconURL(const String& iconURL, const String& type)
+{
+ // FIXME - <rdar://problem/4727645> - At some point in the future, we might actually honor the "type"
+ if (m_iconURL.isEmpty())
+ m_iconURL = iconURL;
+ else if (!type.isEmpty())
+ m_iconURL = iconURL;
+}
+
+void Document::setUseSecureKeyboardEntryWhenActive(bool usesSecureKeyboard)
+{
+ if (m_useSecureKeyboardEntryWhenActive == usesSecureKeyboard)
+ return;
+
+ m_useSecureKeyboardEntryWhenActive = usesSecureKeyboard;
+ m_frame->updateSecureKeyboardEntryIfActive();
+}
+
+bool Document::useSecureKeyboardEntryWhenActive() const
+{
+ return m_useSecureKeyboardEntryWhenActive;
+}
+
+void Document::initSecurityOrigin()
+{
+ if (m_securityOrigin && !m_securityOrigin->isEmpty())
+ return; // m_securityOrigin has already been initialized.
+
+ m_securityOrigin = SecurityOrigin::createForFrame(m_frame);
+}
+
+void Document::setSecurityOrigin(SecurityOrigin* securityOrigin)
+{
+ m_securityOrigin = securityOrigin;
+}
+
+void Document::updateFocusAppearanceSoon()
+{
+ if (!m_updateFocusAppearanceTimer.isActive())
+ m_updateFocusAppearanceTimer.startOneShot(0);
+}
+
+void Document::cancelFocusAppearanceUpdate()
+{
+ m_updateFocusAppearanceTimer.stop();
+}
+
+void Document::updateFocusAppearanceTimerFired(Timer<Document>*)
+{
+ Node* node = focusedNode();
+ if (!node)
+ return;
+ if (!node->isElementNode())
+ return;
+
+ updateLayout();
+
+ Element* element = static_cast<Element*>(node);
+ if (element->isFocusable())
+ element->updateFocusAppearance(false);
+}
+
+// FF method for accessing the selection added for compatability.
+DOMSelection* Document::getSelection() const
+{
+ return frame() ? frame()->domWindow()->getSelection() : 0;
+}
+
+#if ENABLE(DATABASE)
+
+void Document::addOpenDatabase(Database* database)
+{
+ if (!m_openDatabaseSet)
+ m_openDatabaseSet.set(new DatabaseSet);
+
+ ASSERT(!m_openDatabaseSet->contains(database));
+ m_openDatabaseSet->add(database);
+}
+
+void Document::removeOpenDatabase(Database* database)
+{
+ ASSERT(m_openDatabaseSet && m_openDatabaseSet->contains(database));
+ if (!m_openDatabaseSet)
+ return;
+
+ m_openDatabaseSet->remove(database);
+}
+
+DatabaseThread* Document::databaseThread()
+{
+ if (!m_databaseThread && !m_hasOpenDatabases) {
+ // Create the database thread on first request - but not if at least one database was already opened,
+ // because in that case we already had a database thread and terminated it and should not create another.
+ m_databaseThread = new DatabaseThread(this);
+ if (!m_databaseThread->start())
+ m_databaseThread = 0;
+ }
+
+ return m_databaseThread.get();
+}
+
+void Document::stopDatabases()
+{
+ if (m_openDatabaseSet) {
+ DatabaseSet::iterator i = m_openDatabaseSet->begin();
+ DatabaseSet::iterator end = m_openDatabaseSet->end();
+ for (; i != end; ++i) {
+ (*i)->stop();
+ if (m_databaseThread)
+ m_databaseThread->unscheduleDatabaseTasks(*i);
+ }
+ }
+
+ if (m_databaseThread)
+ m_databaseThread->requestTermination();
+}
+
+#endif
+
+} // namespace WebCore
diff --git a/WebCore/dom/Document.h b/WebCore/dom/Document.h
new file mode 100644
index 0000000..14277ea
--- /dev/null
+++ b/WebCore/dom/Document.h
@@ -0,0 +1,960 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * (C) 2006 Alexey Proskuryakov (ap@webkit.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Document_h
+#define Document_h
+
+#include "Attr.h"
+#include "Color.h"
+#include "DeprecatedPtrList.h"
+#include "DeprecatedValueList.h"
+#include "DocumentMarker.h"
+#include "HTMLCollection.h"
+#include "HTMLFormElement.h"
+#include "KURL.h"
+#include "StringHash.h"
+#include "Timer.h"
+#include <wtf/HashCountedSet.h>
+#include <wtf/ListHashSet.h>
+
+// FIXME: We should move Mac off of the old Frame-based user stylesheet loading
+// code and onto the new code in Page. We can't do that until the code in Page
+// supports non-file: URLs, however.
+#if PLATFORM(MAC)
+#define FRAME_LOADS_USER_STYLESHEET 1
+#else
+#define FRAME_LOADS_USER_STYLESHEET 0
+#endif
+
+namespace WebCore {
+
+ class AXObjectCache;
+ class Attr;
+ class Attribute;
+ class CDATASection;
+ class CachedCSSStyleSheet;
+ class CSSStyleDeclaration;
+ class CSSStyleSelector;
+ class CSSStyleSheet;
+ class Comment;
+ class Database;
+ class DOMImplementation;
+ class DOMSelection;
+ class DOMWindow;
+ class DatabaseThread;
+ class DocLoader;
+ class DocumentFragment;
+ class DocumentType;
+ class EditingText;
+ class Element;
+ class EntityReference;
+ class Event;
+ class EventListener;
+ class Frame;
+ class FrameView;
+ class HTMLDocument;
+ class HTMLElement;
+ class HTMLFormControlElementWithState;
+ class HTMLFormElement;
+ class HTMLHeadElement;
+ class HTMLImageLoader;
+ class HTMLInputElement;
+ class HTMLMapElement;
+ class IntPoint;
+ class MouseEventWithHitTestResults;
+ class NameNodeList;
+ class NodeFilter;
+ class NodeIterator;
+ class NodeList;
+ class Page;
+ class PlatformMouseEvent;
+ class ProcessingInstruction;
+ class Range;
+ class RegisteredEventListener;
+ class RenderArena;
+ class SecurityOrigin;
+ class Settings;
+ class StyleSheet;
+ class StyleSheetList;
+ class Text;
+ class TextResourceDecoder;
+ class Tokenizer;
+ class TreeWalker;
+#if ENABLE(XBL)
+ class XBLBindingManager;
+#endif
+#if ENABLE(XPATH)
+ class XPathEvaluator;
+ class XPathExpression;
+ class XPathNSResolver;
+ class XPathResult;
+#endif
+
+ struct DashboardRegionValue;
+ struct HitTestRequest;
+
+#if ENABLE(SVG)
+ class SVGDocumentExtensions;
+#endif
+
+ typedef int ExceptionCode;
+
+class FormElementKey {
+public:
+ FormElementKey(AtomicStringImpl* = 0, AtomicStringImpl* = 0);
+ ~FormElementKey();
+ FormElementKey(const FormElementKey&);
+ FormElementKey& operator=(const FormElementKey&);
+ AtomicStringImpl* name() const { return m_name; }
+ AtomicStringImpl* type() const { return m_type; }
+private:
+ void ref() const;
+ void deref() const;
+ AtomicStringImpl* m_name;
+ AtomicStringImpl* m_type;
+};
+
+inline bool operator==(const FormElementKey& a, const FormElementKey& b)
+ { return a.name() == b.name() && a.type() == b.type(); }
+
+struct FormElementKeyHash {
+ static unsigned hash(const FormElementKey&);
+ static bool equal(const FormElementKey& a, const FormElementKey& b) { return a == b; }
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+struct FormElementKeyHashTraits : WTF::GenericHashTraits<FormElementKey> {
+ static FormElementKey deletedValue();
+};
+
+class Document : public ContainerNode {
+public:
+ Document(DOMImplementation*, Frame*, bool isXHTML = false);
+ virtual ~Document();
+
+ virtual void removedLastRef();
+
+ // Nodes belonging to this document hold "self-only" references -
+ // these are enough to keep the document from being destroyed, but
+ // not enough to keep it from removing its children. This allows a
+ // node that outlives its document to still have a valid document
+ // pointer without introducing reference cycles
+
+ void selfOnlyRef()
+ {
+ ASSERT(!m_deletionHasBegun);
+ ++m_selfOnlyRefCount;
+ }
+ void selfOnlyDeref()
+ {
+ ASSERT(!m_deletionHasBegun);
+ --m_selfOnlyRefCount;
+ if (!m_selfOnlyRefCount && !refCount()) {
+#ifndef NDEBUG
+ m_deletionHasBegun = true;
+#endif
+ delete this;
+ }
+ }
+
+ // DOM methods & attributes for Document
+
+ DocumentType* doctype() const { return m_docType.get(); }
+
+ DOMImplementation* implementation() const;
+ virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
+ Element* documentElement() const;
+ virtual PassRefPtr<Element> createElement(const String& tagName, ExceptionCode&);
+ PassRefPtr<DocumentFragment> createDocumentFragment ();
+ PassRefPtr<Text> createTextNode(const String& data);
+ PassRefPtr<Comment> createComment(const String& data);
+ PassRefPtr<CDATASection> createCDATASection(const String& data, ExceptionCode&);
+ PassRefPtr<ProcessingInstruction> createProcessingInstruction(const String& target, const String& data, ExceptionCode&);
+ PassRefPtr<Attr> createAttribute(const String& name, ExceptionCode& ec) { return createAttributeNS(String(), name, ec); }
+ PassRefPtr<Attr> createAttributeNS(const String& namespaceURI, const String& qualifiedName, ExceptionCode&);
+ PassRefPtr<EntityReference> createEntityReference(const String& name, ExceptionCode&);
+ PassRefPtr<Node> importNode(Node* importedNode, bool deep, ExceptionCode&);
+ virtual PassRefPtr<Element> createElementNS(const String& namespaceURI, const String& qualifiedName, ExceptionCode&);
+ PassRefPtr<Element> createElement(const QualifiedName&, bool createdByParser, ExceptionCode& ec);
+ Element* getElementById(const AtomicString&) const;
+
+ Element* elementFromPoint(int x, int y) const;
+ String readyState() const;
+ String inputEncoding() const;
+ String defaultCharset() const;
+
+ String charset() const { return inputEncoding(); }
+ String characterSet() const { return inputEncoding(); }
+
+ void setCharset(const String&);
+
+ String contentLanguage() const { return m_contentLanguage; }
+ void setContentLanguage(const String& lang) { m_contentLanguage = lang; }
+
+ String xmlEncoding() const { return m_xmlEncoding; }
+ String xmlVersion() const { return m_xmlVersion; }
+ bool xmlStandalone() const { return m_xmlStandalone; }
+
+ void setXMLEncoding(const String& encoding) { m_xmlEncoding = encoding; } // read-only property, only to be set from XMLTokenizer
+ void setXMLVersion(const String&, ExceptionCode&);
+ void setXMLStandalone(bool, ExceptionCode&);
+
+ KURL documentURI() const;
+ void setDocumentURI(const String&);
+
+ virtual KURL baseURI() const;
+
+ PassRefPtr<Node> adoptNode(PassRefPtr<Node> source, ExceptionCode&);
+
+ PassRefPtr<HTMLCollection> images();
+ PassRefPtr<HTMLCollection> embeds();
+ PassRefPtr<HTMLCollection> plugins(); // an alias for embeds() required for the JS DOM bindings.
+ PassRefPtr<HTMLCollection> applets();
+ PassRefPtr<HTMLCollection> links();
+ PassRefPtr<HTMLCollection> forms();
+ PassRefPtr<HTMLCollection> anchors();
+ PassRefPtr<HTMLCollection> all();
+ PassRefPtr<HTMLCollection> objects();
+ PassRefPtr<HTMLCollection> scripts();
+ PassRefPtr<HTMLCollection> windowNamedItems(const String& name);
+ PassRefPtr<HTMLCollection> documentNamedItems(const String& name);
+
+ HTMLCollection::CollectionInfo* collectionInfo(HTMLCollection::Type type)
+ {
+ ASSERT(type >= HTMLCollection::FirstUnnamedDocumentCachedType);
+ unsigned index = type - HTMLCollection::FirstUnnamedDocumentCachedType;
+ ASSERT(index < HTMLCollection::NumUnnamedDocumentCachedTypes);
+ return &m_collectionInfo[index];
+ }
+
+ HTMLCollection::CollectionInfo* nameCollectionInfo(HTMLCollection::Type, const AtomicString& name);
+
+ // DOM methods overridden from parent classes
+
+ virtual String nodeName() const;
+ virtual NodeType nodeType() const;
+
+ // Other methods (not part of DOM)
+ virtual bool isDocumentNode() const { return true; }
+ virtual bool isHTMLDocument() const { return false; }
+ virtual bool isImageDocument() const { return false; }
+#if ENABLE(SVG)
+ virtual bool isSVGDocument() const { return false; }
+#endif
+ virtual bool isPluginDocument() const { return false; }
+
+ CSSStyleSelector* styleSelector() const { return m_styleSelector; }
+
+ Element* getElementByAccessKey(const String& key) const;
+
+ /**
+ * Updates the pending sheet count and then calls updateStyleSelector.
+ */
+ void removePendingSheet();
+
+ /**
+ * This method returns true if all top-level stylesheets have loaded (including
+ * any @imports that they may be loading).
+ */
+ bool haveStylesheetsLoaded() const
+ {
+ return m_pendingStylesheets <= 0 || m_ignorePendingStylesheets
+#if USE(LOW_BANDWIDTH_DISPLAY)
+ || m_inLowBandwidthDisplay
+#endif
+ ;
+ }
+
+ /**
+ * Increments the number of pending sheets. The <link> elements
+ * invoke this to add themselves to the loading list.
+ */
+ void addPendingSheet() { m_pendingStylesheets++; }
+
+ bool gotoAnchorNeededAfterStylesheetsLoad() { return m_gotoAnchorNeededAfterStylesheetsLoad; }
+ void setGotoAnchorNeededAfterStylesheetsLoad(bool b) { m_gotoAnchorNeededAfterStylesheetsLoad = b; }
+
+ /**
+ * Called when one or more stylesheets in the document may have been added, removed or changed.
+ *
+ * Creates a new style selector and assign it to this document. This is done by iterating through all nodes in
+ * document (or those before <BODY> in a HTML document), searching for stylesheets. Stylesheets can be contained in
+ * <LINK>, <STYLE> or <BODY> elements, as well as processing instructions (XML documents only). A list is
+ * constructed from these which is used to create the a new style selector which collates all of the stylesheets
+ * found and is used to calculate the derived styles for all rendering objects.
+ */
+ void updateStyleSelector();
+
+ void recalcStyleSelector();
+
+ bool usesDescendantRules() const { return m_usesDescendantRules; }
+ void setUsesDescendantRules(bool b) { m_usesDescendantRules = b; }
+ bool usesSiblingRules() const { return m_usesSiblingRules; }
+ void setUsesSiblingRules(bool b) { m_usesSiblingRules = b; }
+ bool usesFirstLineRules() const { return m_usesFirstLineRules; }
+ void setUsesFirstLineRules(bool b) { m_usesFirstLineRules = b; }
+ bool usesFirstLetterRules() const { return m_usesFirstLetterRules; }
+ void setUsesFirstLetterRules(bool b) { m_usesFirstLetterRules = b; }
+
+ // Machinery for saving and restoring state when you leave and then go back to a page.
+ void registerFormElementWithState(HTMLFormControlElementWithState* e) { m_formElementsWithState.add(e); }
+ void unregisterFormElementWithState(HTMLFormControlElementWithState* e) { m_formElementsWithState.remove(e); }
+ Vector<String> formElementsState() const;
+ void setStateForNewFormElements(const Vector<String>&);
+ bool hasStateForNewFormElements() const;
+ bool takeStateForFormElement(AtomicStringImpl* name, AtomicStringImpl* type, String& state);
+
+ FrameView* view() const; // can be NULL
+ Frame* frame() const { return m_frame; } // can be NULL
+ Page* page() const; // can be NULL
+ Settings* settings() const; // can be NULL
+
+ PassRefPtr<Range> createRange();
+
+ PassRefPtr<NodeIterator> createNodeIterator(Node* root, unsigned whatToShow,
+ PassRefPtr<NodeFilter>, bool expandEntityReferences, ExceptionCode&);
+
+ PassRefPtr<TreeWalker> createTreeWalker(Node* root, unsigned whatToShow,
+ PassRefPtr<NodeFilter>, bool expandEntityReferences, ExceptionCode&);
+
+ // Special support for editing
+ PassRefPtr<CSSStyleDeclaration> createCSSStyleDeclaration();
+ PassRefPtr<EditingText> createEditingTextNode(const String&);
+
+ virtual void recalcStyle( StyleChange = NoChange );
+ static DeprecatedPtrList<Document>* changedDocuments;
+ virtual void updateRendering();
+ void updateLayout();
+ void updateLayoutIgnorePendingStylesheets();
+ static void updateDocumentsRendering();
+ DocLoader* docLoader() { return m_docLoader; }
+
+ virtual void attach();
+ virtual void detach();
+
+ RenderArena* renderArena() { return m_renderArena; }
+
+ AXObjectCache* axObjectCache() const;
+
+ // to get visually ordered hebrew and arabic pages right
+ void setVisuallyOrdered();
+
+ void open();
+ void implicitOpen();
+ void close();
+ void implicitClose();
+ void cancelParsing();
+
+ void write(const String& text);
+ void writeln(const String& text);
+ void finishParsing();
+ void clear();
+
+ bool wellFormed() const { return m_wellFormed; }
+
+ const KURL& url() const { return m_url.isEmpty() ? blankURL() : m_url; }
+ void setURL(const KURL&);
+
+ const KURL& baseURL() const { return m_baseURL.isEmpty() ? url() : m_baseURL; }
+ void setBaseURL(const KURL&);
+
+ const String& baseTarget() const { return m_baseTarget; }
+ void setBaseTarget(const String& baseTarget) { m_baseTarget = baseTarget; }
+
+ KURL completeURL(const String&);
+
+ // from cachedObjectClient
+ virtual void setCSSStyleSheet(const String& url, const String& charset, const CachedCSSStyleSheet*);
+
+#if FRAME_LOADS_USER_STYLESHEET
+ void setUserStyleSheet(const String& sheet);
+#endif
+
+ String userStyleSheet() const;
+
+ CSSStyleSheet* elementSheet();
+ CSSStyleSheet* mappedElementSheet();
+ virtual Tokenizer* createTokenizer();
+ Tokenizer* tokenizer() { return m_tokenizer; }
+
+ bool printing() const { return m_printing; }
+ void setPrinting(bool p) { m_printing = p; }
+
+ enum ParseMode { Compat, AlmostStrict, Strict };
+
+private:
+ virtual void determineParseMode() {}
+
+public:
+ void setParseMode(ParseMode m) { m_parseMode = m; }
+ ParseMode parseMode() const { return m_parseMode; }
+
+ bool inCompatMode() const { return m_parseMode == Compat; }
+ bool inAlmostStrictMode() const { return m_parseMode == AlmostStrict; }
+ bool inStrictMode() const { return m_parseMode == Strict; }
+
+ void setParsing(bool);
+ bool parsing() const { return m_bParsing; }
+ int minimumLayoutDelay();
+ bool shouldScheduleLayout();
+ int elapsedTime() const;
+
+ void setTextColor(const Color& color) { m_textColor = color; }
+ Color textColor() const { return m_textColor; }
+
+ const Color& linkColor() const { return m_linkColor; }
+ const Color& visitedLinkColor() const { return m_visitedLinkColor; }
+ const Color& activeLinkColor() const { return m_activeLinkColor; }
+ void setLinkColor(const Color& c) { m_linkColor = c; }
+ void setVisitedLinkColor(const Color& c) { m_visitedLinkColor = c; }
+ void setActiveLinkColor(const Color& c) { m_activeLinkColor = c; }
+ void resetLinkColor();
+ void resetVisitedLinkColor();
+ void resetActiveLinkColor();
+
+ MouseEventWithHitTestResults prepareMouseEvent(const HitTestRequest&, const IntPoint&, const PlatformMouseEvent&);
+
+ virtual bool childTypeAllowed(NodeType);
+ virtual PassRefPtr<Node> cloneNode(bool deep);
+
+ virtual bool canReplaceChild(Node* newChild, Node* oldChild);
+
+ StyleSheetList* styleSheets();
+
+ /* Newly proposed CSS3 mechanism for selecting alternate
+ stylesheets using the DOM. May be subject to change as
+ spec matures. - dwh
+ */
+ String preferredStylesheetSet() const;
+ String selectedStylesheetSet() const;
+ void setSelectedStylesheetSet(const String&);
+
+ bool setFocusedNode(PassRefPtr<Node>);
+ Node* focusedNode() const { return m_focusedNode.get(); }
+
+ void setHoverNode(PassRefPtr<Node>);
+ Node* hoverNode() const { return m_hoverNode.get(); }
+
+ void setActiveNode(PassRefPtr<Node>);
+ Node* activeNode() const { return m_activeNode.get(); }
+
+ void focusedNodeRemoved();
+ void removeFocusedNodeOfSubtree(Node*, bool amongChildrenOnly = false);
+ void hoveredNodeDetached(Node*);
+ void activeChainNodeDetached(Node*);
+
+ // Updates for :target (CSS3 selector).
+ void setCSSTarget(Node*);
+ Node* getCSSTarget() const;
+
+ void setDocumentChanged(bool);
+
+ void attachNodeIterator(NodeIterator*);
+ void detachNodeIterator(NodeIterator*);
+ void notifyBeforeNodeRemoval(Node*);
+ DOMWindow* defaultView() const;
+ PassRefPtr<Event> createEvent(const String& eventType, ExceptionCode&);
+
+ // keep track of what types of event listeners are registered, so we don't
+ // dispatch events unnecessarily
+ enum ListenerType {
+ DOMSUBTREEMODIFIED_LISTENER = 0x01,
+ DOMNODEINSERTED_LISTENER = 0x02,
+ DOMNODEREMOVED_LISTENER = 0x04,
+ DOMNODEREMOVEDFROMDOCUMENT_LISTENER = 0x08,
+ DOMNODEINSERTEDINTODOCUMENT_LISTENER = 0x10,
+ DOMATTRMODIFIED_LISTENER = 0x20,
+ DOMCHARACTERDATAMODIFIED_LISTENER = 0x40,
+ OVERFLOWCHANGED_LISTENER = 0x80
+ };
+
+ bool hasListenerType(ListenerType listenerType) const { return (m_listenerTypes & listenerType); }
+ void addListenerType(ListenerType listenerType) { m_listenerTypes = m_listenerTypes | listenerType; }
+
+ CSSStyleDeclaration* getOverrideStyle(Element*, const String& pseudoElt);
+
+ void handleWindowEvent(Event*, bool useCapture);
+ void setHTMLWindowEventListener(const AtomicString &eventType, PassRefPtr<EventListener>);
+ EventListener* getHTMLWindowEventListener(const AtomicString &eventType);
+ void removeHTMLWindowEventListener(const AtomicString &eventType);
+
+ void setHTMLWindowEventListener(const AtomicString& eventType, Attribute*);
+
+ void addWindowEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture);
+ void removeWindowEventListener(const AtomicString& eventType, EventListener*, bool useCapture);
+ bool hasWindowEventListener(const AtomicString& eventType);
+
+ PassRefPtr<EventListener> createHTMLEventListener(const String& functionName, const String& code, Node*);
+
+ /**
+ * Searches through the document, starting from fromNode, for the next selectable element that comes after fromNode.
+ * The order followed is as specified in section 17.11.1 of the HTML4 spec, which is elements with tab indexes
+ * first (from lowest to highest), and then elements without tab indexes (in document order).
+ *
+ * @param fromNode The node from which to start searching. The node after this will be focused. May be null.
+ *
+ * @return The focus node that comes after fromNode
+ *
+ * See http://www.w3.org/TR/html4/interact/forms.html#h-17.11.1
+ */
+ Node* nextFocusableNode(Node* start, KeyboardEvent*);
+
+ /**
+ * Searches through the document, starting from fromNode, for the previous selectable element (that comes _before_)
+ * fromNode. The order followed is as specified in section 17.11.1 of the HTML4 spec, which is elements with tab
+ * indexes first (from lowest to highest), and then elements without tab indexes (in document order).
+ *
+ * @param fromNode The node from which to start searching. The node before this will be focused. May be null.
+ *
+ * @return The focus node that comes before fromNode
+ *
+ * See http://www.w3.org/TR/html4/interact/forms.html#h-17.11.1
+ */
+ Node* previousFocusableNode(Node* start, KeyboardEvent*);
+
+ int nodeAbsIndex(Node*);
+ Node* nodeWithAbsIndex(int absIndex);
+
+ /**
+ * Handles a HTTP header equivalent set by a meta tag using <meta http-equiv="..." content="...">. This is called
+ * when a meta tag is encountered during document parsing, and also when a script dynamically changes or adds a meta
+ * tag. This enables scripts to use meta tags to perform refreshes and set expiry dates in addition to them being
+ * specified in a HTML file.
+ *
+ * @param equiv The http header name (value of the meta tag's "equiv" attribute)
+ * @param content The header value (value of the meta tag's "content" attribute)
+ */
+ void processHttpEquiv(const String& equiv, const String& content);
+
+ void dispatchImageLoadEventSoon(HTMLImageLoader*);
+ void dispatchImageLoadEventsNow();
+ void removeImage(HTMLImageLoader*);
+
+ // Returns the owning element in the parent document.
+ // Returns 0 if this is the top level document.
+ Element* ownerElement() const;
+
+ String title() const { return m_title; }
+ void setTitle(const String&, Element* titleElement = 0);
+ void removeTitle(Element* titleElement);
+
+ String cookie() const;
+ void setCookie(const String&);
+
+ String referrer() const;
+
+ String domain() const;
+ void setDomain(const String& newDomain);
+
+ String lastModified() const;
+
+ const KURL& policyBaseURL() const { return m_policyBaseURL; }
+ void setPolicyBaseURL(const KURL& url) { m_policyBaseURL = url; }
+
+ // The following implements the rule from HTML 4 for what valid names are.
+ // To get this right for all the XML cases, we probably have to improve this or move it
+ // and make it sensitive to the type of document.
+ static bool isValidName(const String&);
+
+ // The following breaks a qualified name into a prefix and a local name.
+ // It also does a validity check, and returns false if the qualified name is invalid
+ // (empty string or invalid characters).
+ static bool parseQualifiedName(const String& qualifiedName, String& prefix, String& localName);
+
+ void addElementById(const AtomicString& elementId, Element *element);
+ void removeElementById(const AtomicString& elementId, Element *element);
+
+ void addImageMap(HTMLMapElement*);
+ void removeImageMap(HTMLMapElement*);
+ HTMLMapElement* getImageMap(const String& url) const;
+
+ HTMLElement* body();
+ void setBody(PassRefPtr<HTMLElement>, ExceptionCode&);
+
+ HTMLHeadElement* head();
+
+ String toString() const;
+
+ bool execCommand(const String& command, bool userInterface = false, const String& value = String());
+ bool queryCommandEnabled(const String& command);
+ bool queryCommandIndeterm(const String& command);
+ bool queryCommandState(const String& command);
+ bool queryCommandSupported(const String& command);
+ String queryCommandValue(const String& command);
+
+ void addMarker(Range*, DocumentMarker::MarkerType, String description = String());
+ void addMarker(Node*, DocumentMarker);
+ void copyMarkers(Node *srcNode, unsigned startOffset, int length, Node *dstNode, int delta, DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
+ void removeMarkers(Range*, DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
+ void removeMarkers(Node*, unsigned startOffset, int length, DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
+ void removeMarkers(DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
+ void removeMarkers(Node*);
+ void repaintMarkers(DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
+ void setRenderedRectForMarker(Node*, DocumentMarker, const IntRect&);
+ void invalidateRenderedRectsForMarkersInRect(const IntRect&);
+ void shiftMarkers(Node*, unsigned startOffset, int delta, DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
+
+ DocumentMarker* markerContainingPoint(const IntPoint&, DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
+ Vector<DocumentMarker> markersForNode(Node*);
+ Vector<IntRect> renderedRectsForMarkers(DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
+
+ // designMode support
+ enum InheritedBool { off = false, on = true, inherit };
+ void setDesignMode(InheritedBool value);
+ InheritedBool getDesignMode() const;
+ bool inDesignMode() const;
+
+ Document* parentDocument() const;
+ Document* topDocument() const;
+
+ int docID() const { return m_docID; }
+
+#if ENABLE(XSLT)
+ void applyXSLTransform(ProcessingInstruction* pi);
+ void setTransformSource(void* doc);
+ const void* transformSource() { return m_transformSource; }
+ PassRefPtr<Document> transformSourceDocument() { return m_transformSourceDocument; }
+ void setTransformSourceDocument(Document* doc) { m_transformSourceDocument = doc; }
+#endif
+
+#if ENABLE(XBL)
+ // XBL methods
+ XBLBindingManager* bindingManager() const { return m_bindingManager; }
+#endif
+
+ void incDOMTreeVersion() { ++m_domtree_version; }
+ unsigned domTreeVersion() const { return m_domtree_version; }
+
+ void setDocType(PassRefPtr<DocumentType>);
+
+ void finishedParsing();
+
+#if ENABLE(XPATH)
+ // XPathEvaluator methods
+ PassRefPtr<XPathExpression> createExpression(const String& expression,
+ XPathNSResolver* resolver,
+ ExceptionCode& ec);
+ PassRefPtr<XPathNSResolver> createNSResolver(Node *nodeResolver);
+ PassRefPtr<XPathResult> evaluate(const String& expression,
+ Node* contextNode,
+ XPathNSResolver* resolver,
+ unsigned short type,
+ XPathResult* result,
+ ExceptionCode& ec);
+#endif // ENABLE(XPATH)
+
+ enum PendingSheetLayout { NoLayoutWithPendingSheets, DidLayoutWithPendingSheets, IgnoreLayoutWithPendingSheets };
+
+ bool didLayoutWithPendingStylesheets() const { return m_pendingSheetLayout == DidLayoutWithPendingSheets; }
+
+ void setHasNodesWithPlaceholderStyle() { m_hasNodesWithPlaceholderStyle = true; }
+
+ String iconURL();
+ void setIconURL(const String& iconURL, const String& type);
+
+ bool isAllowedToLoadLocalResources() const { return m_isAllowedToLoadLocalResources; }
+
+ void setUseSecureKeyboardEntryWhenActive(bool);
+ bool useSecureKeyboardEntryWhenActive() const;
+
+#if USE(LOW_BANDWIDTH_DISPLAY)
+ void setDocLoader(DocLoader* loader) { m_docLoader = loader; }
+ bool inLowBandwidthDisplay() const { return m_inLowBandwidthDisplay; }
+ void setLowBandwidthDisplay(bool lowBandWidth) { m_inLowBandwidthDisplay = lowBandWidth; }
+#endif
+
+ void addNodeList() { m_numNodeLists++; }
+ void removeNodeList() { m_numNodeLists--; }
+ bool hasNodeLists() const { return m_numNodeLists != 0; }
+
+ void updateFocusAppearanceSoon();
+ void cancelFocusAppearanceUpdate();
+
+ // FF method for accessing the selection added for compatability.
+ DOMSelection* getSelection() const;
+
+private:
+ CSSStyleSelector* m_styleSelector;
+ bool m_didCalculateStyleSelector;
+
+ Frame* m_frame;
+ DocLoader* m_docLoader;
+ Tokenizer* m_tokenizer;
+ bool m_wellFormed;
+ KURL m_url;
+ KURL m_baseURL;
+ String m_baseTarget;
+
+ RefPtr<DocumentType> m_docType;
+ RefPtr<DOMImplementation> m_implementation;
+
+ RefPtr<StyleSheet> m_sheet;
+#if FRAME_LOADS_USER_STYLESHEET
+ String m_usersheet;
+#endif
+
+ // Track the number of currently loading top-level stylesheets. Sheets
+ // loaded using the @import directive are not included in this count.
+ // We use this count of pending sheets to detect when we can begin attaching
+ // elements.
+ int m_pendingStylesheets;
+
+ // But sometimes you need to ignore pending stylesheet count to
+ // force an immediate layout when requested by JS.
+ bool m_ignorePendingStylesheets;
+
+ // If we do ignore the pending stylesheet count, then we need to add a boolean
+ // to track that this happened so that we can do a full repaint when the stylesheets
+ // do eventually load.
+ PendingSheetLayout m_pendingSheetLayout;
+
+ bool m_hasNodesWithPlaceholderStyle;
+
+ RefPtr<CSSStyleSheet> m_elemSheet;
+ RefPtr<CSSStyleSheet> m_mappedElementSheet;
+
+ bool m_printing;
+
+ ParseMode m_parseMode;
+
+ Color m_textColor;
+
+ RefPtr<Node> m_focusedNode;
+ RefPtr<Node> m_hoverNode;
+ RefPtr<Node> m_activeNode;
+ mutable RefPtr<Element> m_documentElement;
+
+ unsigned m_domtree_version;
+
+ HashSet<NodeIterator*> m_nodeIterators;
+
+ unsigned short m_listenerTypes;
+ RefPtr<StyleSheetList> m_styleSheets;
+
+ RegisteredEventListenerList m_windowEventListeners;
+
+ typedef HashMap<FormElementKey, Vector<String>, FormElementKeyHash, FormElementKeyHashTraits> FormElementStateMap;
+ ListHashSet<HTMLFormControlElementWithState*> m_formElementsWithState;
+ FormElementStateMap m_stateForNewFormElements;
+
+ Color m_linkColor;
+ Color m_visitedLinkColor;
+ Color m_activeLinkColor;
+
+ String m_preferredStylesheetSet;
+ String m_selectedStylesheetSet;
+
+ bool m_loadingSheet;
+ bool visuallyOrdered;
+ bool m_bParsing;
+ bool m_docChanged;
+ bool m_inStyleRecalc;
+ bool m_closeAfterStyleRecalc;
+ bool m_usesDescendantRules;
+ bool m_usesSiblingRules;
+ bool m_usesFirstLineRules;
+ bool m_usesFirstLetterRules;
+ bool m_gotoAnchorNeededAfterStylesheetsLoad;
+
+ String m_title;
+ bool m_titleSetExplicitly;
+ RefPtr<Element> m_titleElement;
+
+ RenderArena* m_renderArena;
+
+ typedef std::pair<Vector<DocumentMarker>, Vector<IntRect> > MarkerMapVectorPair;
+ typedef HashMap<RefPtr<Node>, MarkerMapVectorPair*> MarkerMap;
+ MarkerMap m_markers;
+
+ mutable AXObjectCache* m_axObjectCache;
+
+ DeprecatedPtrList<HTMLImageLoader> m_imageLoadEventDispatchSoonList;
+ DeprecatedPtrList<HTMLImageLoader> m_imageLoadEventDispatchingList;
+ Timer<Document> m_imageLoadEventTimer;
+
+ Timer<Document> m_updateFocusAppearanceTimer;
+
+ Node* m_cssTarget;
+
+ bool m_processingLoadEvent;
+ double m_startTime;
+ bool m_overMinimumLayoutThreshold;
+
+#if ENABLE(XSLT)
+ void* m_transformSource;
+ RefPtr<Document> m_transformSourceDocument;
+#endif
+
+#if ENABLE(XBL)
+ XBLBindingManager* m_bindingManager; // The access point through which documents and elements communicate with XBL.
+#endif
+
+ typedef HashMap<AtomicStringImpl*, HTMLMapElement*> ImageMapsByName;
+ ImageMapsByName m_imageMapsByName;
+
+ KURL m_policyBaseURL;
+
+ HashSet<Node*> m_disconnectedNodesWithEventListeners;
+
+ int m_docID; // A unique document identifier used for things like document-specific mapped attributes.
+
+ String m_xmlEncoding;
+ String m_xmlVersion;
+ bool m_xmlStandalone;
+
+ String m_contentLanguage;
+
+public:
+ bool inPageCache();
+ void setInPageCache(bool flag);
+
+ // Elements can register themselves for the "willSaveToCache()" and
+ // "didRestoreFromCache()" callbacks
+ void registerForCacheCallbacks(Element*);
+ void unregisterForCacheCallbacks(Element*);
+ void willSaveToCache();
+ void didRestoreFromCache();
+
+ void setShouldCreateRenderers(bool);
+ bool shouldCreateRenderers();
+
+ void setDecoder(TextResourceDecoder*);
+ TextResourceDecoder* decoder() const { return m_decoder.get(); }
+
+ UChar backslashAsCurrencySymbol() const;
+
+ void setDashboardRegionsDirty(bool f) { m_dashboardRegionsDirty = f; }
+ bool dashboardRegionsDirty() const { return m_dashboardRegionsDirty; }
+ bool hasDashboardRegions () const { return m_hasDashboardRegions; }
+ void setHasDashboardRegions (bool f) { m_hasDashboardRegions = f; }
+ const Vector<DashboardRegionValue>& dashboardRegions() const;
+ void setDashboardRegions(const Vector<DashboardRegionValue>&);
+
+ void removeAllEventListenersFromAllNodes();
+
+ void registerDisconnectedNodeWithEventListeners(Node*);
+ void unregisterDisconnectedNodeWithEventListeners(Node*);
+
+ HTMLFormElement::CheckedRadioButtons& checkedRadioButtons() { return m_checkedRadioButtons; }
+
+#if ENABLE(SVG)
+ const SVGDocumentExtensions* svgExtensions();
+ SVGDocumentExtensions* accessSVGExtensions();
+#endif
+
+ void initSecurityOrigin();
+ SecurityOrigin* securityOrigin() const { return m_securityOrigin.get(); }
+
+ // Explicitly override the security origin for this document.
+ // Note: It is dangerous to change the security origin of a document
+ // that already contains content.
+ void setSecurityOrigin(SecurityOrigin*);
+
+ bool processingLoadEvent() const { return m_processingLoadEvent; }
+
+#if ENABLE(DATABASE)
+ void addOpenDatabase(Database*);
+ void removeOpenDatabase(Database*);
+ DatabaseThread* databaseThread(); // Creates the thread as needed, but not if it has been already terminated.
+ void setHasOpenDatabases() { m_hasOpenDatabases = true; }
+ bool hasOpenDatabases() { return m_hasOpenDatabases; }
+ void stopDatabases();
+#endif
+protected:
+ void clearXMLVersion() { m_xmlVersion = String(); }
+
+private:
+ bool shouldBeAllowedToLoadLocalResources() const;
+
+ void updateTitle();
+ void removeAllDisconnectedNodeEventListeners();
+ void imageLoadEventTimerFired(Timer<Document>*);
+ void updateFocusAppearanceTimerFired(Timer<Document>*);
+
+ RefPtr<SecurityOrigin> m_securityOrigin;
+
+ RenderObject* m_savedRenderer;
+ int m_secureForms;
+
+ RefPtr<TextResourceDecoder> m_decoder;
+
+ // We maintain the invariant that m_duplicateIds is the count of all elements with a given ID
+ // excluding the one referenced in m_elementsById, if any. This means it one less than the total count
+ // when the first node with a given ID is cached, otherwise the same as the total count.
+ mutable HashMap<AtomicStringImpl*, Element*> m_elementsById;
+ mutable HashCountedSet<AtomicStringImpl*> m_duplicateIds;
+
+ mutable HashMap<StringImpl*, Element*, CaseFoldingHash> m_elementsByAccessKey;
+
+ InheritedBool m_designMode;
+
+ int m_selfOnlyRefCount;
+
+ HTMLFormElement::CheckedRadioButtons m_checkedRadioButtons;
+
+ typedef HashMap<AtomicStringImpl*, HTMLCollection::CollectionInfo*> NamedCollectionMap;
+ HTMLCollection::CollectionInfo m_collectionInfo[HTMLCollection::NumUnnamedDocumentCachedTypes];
+ NamedCollectionMap m_nameCollectionInfo[HTMLCollection::NumNamedDocumentCachedTypes];
+
+#if ENABLE(XPATH)
+ RefPtr<XPathEvaluator> m_xpathEvaluator;
+#endif
+
+#if ENABLE(SVG)
+ SVGDocumentExtensions* m_svgExtensions;
+#endif
+
+ Vector<DashboardRegionValue> m_dashboardRegions;
+ bool m_hasDashboardRegions;
+ bool m_dashboardRegionsDirty;
+
+ mutable bool m_accessKeyMapValid;
+ bool m_createRenderers;
+ bool m_inPageCache;
+ String m_iconURL;
+
+ HashSet<Element*> m_pageCacheCallbackElements;
+
+ bool m_isAllowedToLoadLocalResources;
+
+ bool m_useSecureKeyboardEntryWhenActive;
+
+ bool m_isXHTML;
+
+ unsigned m_numNodeLists;
+
+#if ENABLE(DATABASE)
+ RefPtr<DatabaseThread> m_databaseThread;
+ bool m_hasOpenDatabases; // This never changes back to false, even as the database thread is closed.
+ typedef HashSet<Database*> DatabaseSet;
+ OwnPtr<DatabaseSet> m_openDatabaseSet;
+#endif
+#if USE(LOW_BANDWIDTH_DISPLAY)
+ bool m_inLowBandwidthDisplay;
+#endif
+};
+
+} // namespace WebCore
+
+#endif // Document_h
diff --git a/WebCore/dom/Document.idl b/WebCore/dom/Document.idl
new file mode 100644
index 0000000..ddc25f3
--- /dev/null
+++ b/WebCore/dom/Document.idl
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007 Samuel Weinig <sam@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module core {
+
+ interface [
+ GenerateConstructor,
+ GenerateToJS,
+ CustomMarkFunction,
+ InterfaceUUID=48BB95FC-2D08-4c54-BE65-7558736A4CAE,
+ ImplementationUUID=FF5CBE81-F817-429c-A6C2-0CCCD2328062
+ ] Document : EventTargetNode {
+
+ // DOM Level 1 Core
+ readonly attribute DocumentType doctype;
+ readonly attribute DOMImplementation implementation;
+ readonly attribute Element documentElement;
+
+ Element createElement(in DOMString tagName)
+ raises (DOMException);
+ DocumentFragment createDocumentFragment();
+ Text createTextNode(in DOMString data);
+ Comment createComment(in DOMString data);
+ CDATASection createCDATASection(in DOMString data)
+ raises(DOMException);
+ [OldStyleObjC] ProcessingInstruction createProcessingInstruction(in DOMString target,
+ in DOMString data)
+ raises (DOMException);
+ Attr createAttribute(in DOMString name)
+ raises (DOMException);
+ EntityReference createEntityReference(in DOMString name)
+ raises(DOMException);
+ NodeList getElementsByTagName(in DOMString tagname);
+
+ // Introduced in DOM Level 2:
+
+ [OldStyleObjC] Node importNode(in Node importedNode,
+ in boolean deep)
+ raises (DOMException);
+ [OldStyleObjC] Element createElementNS(in [ConvertNullToNullString] DOMString namespaceURI,
+ in DOMString qualifiedName)
+ raises (DOMException);
+ [OldStyleObjC] Attr createAttributeNS(in [ConvertNullToNullString] DOMString namespaceURI,
+ in DOMString qualifiedName)
+ raises (DOMException);
+ [OldStyleObjC] NodeList getElementsByTagNameNS(in [ConvertNullToNullString] DOMString namespaceURI,
+ in DOMString localName);
+ Element getElementById(in DOMString elementId);
+
+ // DOM Level 3 Core
+
+ readonly attribute [ConvertNullStringTo=Null] DOMString inputEncoding;
+
+ readonly attribute [ConvertNullStringTo=Null] DOMString xmlEncoding;
+ attribute [ConvertNullStringTo=Null, ConvertNullToNullString] DOMString xmlVersion
+ setter raises (DOMException);
+ attribute boolean xmlStandalone
+ setter raises (DOMException);
+
+ Node adoptNode(in Node source)
+ raises (DOMException);
+
+ attribute [ConvertNullStringTo=Null, ConvertNullToNullString] DOMString documentURI;
+
+#if !defined(LANGUAGE_COM)
+ // DOM Level 2 Events (DocumentEvents interface)
+
+ Event createEvent(in DOMString eventType)
+ raises(DOMException);
+
+ // DOM Level 2 Tranversal and Range (DocumentRange interface)
+
+ Range createRange();
+
+ // DOM Level 2 Tranversal and Range (DocumentTraversal interface)
+
+#if !defined(LANGUAGE_OBJECTIVE_C)
+ NodeIterator createNodeIterator(in Node root,
+ in unsigned long whatToShow,
+ in NodeFilter filter,
+ in boolean entityReferenceExpansion)
+ raises(DOMException);
+ TreeWalker createTreeWalker(in Node root,
+ in unsigned long whatToShow,
+ in NodeFilter filter,
+ in boolean entityReferenceExpansion)
+ raises(DOMException);
+#endif // !defined(LANGUAGE_OBJECTIVE_C)
+
+ // DOM Level 2 Abstract Views (DocumentView interface)
+
+ readonly attribute DOMWindow defaultView;
+
+ // DOM Level 2 Style (DocumentStyle interface)
+
+ readonly attribute StyleSheetList styleSheets;
+
+ // DOM Level 2 Style (DocumentCSS interface)
+
+ [OldStyleObjC] CSSStyleDeclaration getOverrideStyle(in Element element,
+ in DOMString pseudoElement);
+#ifdef ENABLE_XPATH
+ // DOM Level 3 XPath (XPathEvaluator interface)
+ [OldStyleObjC] XPathExpression createExpression(in DOMString expression,
+ in XPathNSResolver resolver)
+ raises(DOMException);
+ XPathNSResolver createNSResolver(in Node nodeResolver);
+ [OldStyleObjC] XPathResult evaluate(in DOMString expression,
+ in Node contextNode,
+ in XPathNSResolver resolver,
+ in unsigned short type,
+ in XPathResult inResult)
+ raises(DOMException);
+#endif // ENABLE_XPATH
+#endif // !defined(LANGUAGE_COM)
+
+ // Common extensions
+
+ boolean execCommand(in DOMString command,
+ in boolean userInterface,
+ in [ConvertUndefinedOrNullToNullString] DOMString value);
+
+#if defined(LANGUAGE_OBJECTIVE_C)
+ // FIXME: remove the these two versions once [Optional] is implemented for Objective-C.
+ boolean execCommand(in DOMString command,
+ in boolean userInterface);
+ boolean execCommand(in DOMString command);
+#endif
+
+ boolean queryCommandEnabled(in DOMString command);
+ boolean queryCommandIndeterm(in DOMString command);
+ boolean queryCommandState(in DOMString command);
+ boolean queryCommandSupported(in DOMString command);
+ [ConvertNullStringTo=False] DOMString queryCommandValue(in DOMString command);
+
+ // Moved down from HTMLDocument
+
+ attribute [ConvertNullToNullString] DOMString title;
+ readonly attribute DOMString referrer;
+#if defined(LANGUAGE_JAVASCRIPT)
+ attribute [ConvertNullToNullString] DOMString domain;
+#else
+ readonly attribute DOMString domain;
+#endif
+ readonly attribute DOMString URL;
+
+ // FIXME: the DOM spec states that this attribute can
+ // raise an exception on setting.
+ attribute [ConvertNullToNullString] DOMString cookie
+ /*setter raises (DOMException)*/;
+
+ // FIXME: the DOM spec does NOT have this attribute
+ // raising an exception.
+ attribute HTMLElement body
+ setter raises (DOMException);
+
+ readonly attribute HTMLCollection images;
+ readonly attribute HTMLCollection applets;
+ readonly attribute HTMLCollection links;
+ readonly attribute HTMLCollection forms;
+ readonly attribute HTMLCollection anchors;
+ readonly attribute DOMString lastModified;
+
+ NodeList getElementsByName(in DOMString elementName);
+
+#if defined(LANGUAGE_JAVASCRIPT)
+ attribute [Custom] Location location;
+#endif
+
+ // IE extensions
+
+ attribute [ConvertNullStringTo=Undefined, ConvertNullToNullString] DOMString charset;
+ readonly attribute [ConvertNullStringTo=Undefined] DOMString defaultCharset;
+ readonly attribute [ConvertNullStringTo=Undefined] DOMString readyState;
+
+ Element elementFromPoint(in long x, in long y);
+
+ // Mozilla extensions
+#if defined(LANGUAGE_JAVASCRIPT)
+ DOMSelection getSelection();
+#endif
+ readonly attribute [ConvertNullStringTo=Null] DOMString characterSet;
+
+ // WebKit extensions
+
+ readonly attribute [ConvertNullStringTo=Null] DOMString preferredStylesheetSet;
+ attribute [ConvertNullStringTo=Null, ConvertNullToNullString] DOMString selectedStylesheetSet;
+
+#if !defined(LANGUAGE_COM)
+#if !defined(LANGUAGE_JAVASCRIPT)
+ CSSStyleDeclaration createCSSStyleDeclaration();
+#endif
+#endif
+
+#if defined(LANGUAGE_OBJECTIVE_C)
+ // DOM Level 2 Style Interface
+ [OldStyleObjC, UsesView] CSSStyleDeclaration getComputedStyle(in Element element,
+ in DOMString pseudoElement);
+
+ // WebKit extension
+ // FIXME: remove the first version once [Optional] is implemented for Objective-C.
+ [UsesView] CSSRuleList getMatchedCSSRules(in Element element,
+ in DOMString pseudoElement);
+ [UsesView] CSSRuleList getMatchedCSSRules(in Element element,
+ in DOMString pseudoElement,
+ in [Optional] boolean authorOnly);
+#endif
+
+ // HTML 5
+ NodeList getElementsByClassName(in DOMString tagname);
+
+ // DocumentSelector - Selector API
+ Element querySelector(in [ConvertUndefinedOrNullToNullString] DOMString selectors)
+ raises(DOMException);
+ NodeList querySelectorAll(in [ConvertUndefinedOrNullToNullString] DOMString selectors)
+ raises(DOMException);
+ };
+
+}
diff --git a/WebCore/dom/DocumentFragment.cpp b/WebCore/dom/DocumentFragment.cpp
new file mode 100644
index 0000000..298f1b9
--- /dev/null
+++ b/WebCore/dom/DocumentFragment.cpp
@@ -0,0 +1,77 @@
+/**
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include "DocumentFragment.h"
+
+namespace WebCore {
+
+DocumentFragment::DocumentFragment(Document *doc) : ContainerNode(doc)
+{
+}
+
+String DocumentFragment::nodeName() const
+{
+ return "#document-fragment";
+}
+
+Node::NodeType DocumentFragment::nodeType() const
+{
+ return DOCUMENT_FRAGMENT_NODE;
+}
+
+// DOM Section 1.1.1
+bool DocumentFragment::childTypeAllowed(NodeType type)
+{
+ switch (type) {
+ case ELEMENT_NODE:
+ case PROCESSING_INSTRUCTION_NODE:
+ case COMMENT_NODE:
+ case TEXT_NODE:
+ case CDATA_SECTION_NODE:
+ case ENTITY_REFERENCE_NODE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+String DocumentFragment::toString() const
+{
+ String result;
+ for (Node *child = firstChild(); child != NULL; child = child->nextSibling())
+ result += child->toString();
+ return result;
+}
+
+PassRefPtr<Node> DocumentFragment::cloneNode(bool deep)
+{
+ RefPtr<DocumentFragment> clone = new DocumentFragment(document());
+ if (deep)
+ cloneChildNodes(clone.get());
+ return clone.release();
+}
+
+}
diff --git a/WebCore/dom/DocumentFragment.h b/WebCore/dom/DocumentFragment.h
new file mode 100644
index 0000000..db5e808
--- /dev/null
+++ b/WebCore/dom/DocumentFragment.h
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef DocumentFragment_h
+#define DocumentFragment_h
+
+#include "ContainerNode.h"
+
+namespace WebCore {
+
+class DocumentFragment : public ContainerNode
+{
+public:
+ DocumentFragment(Document*);
+
+ virtual String nodeName() const;
+ virtual NodeType nodeType() const;
+ virtual PassRefPtr<Node> cloneNode(bool deep);
+ virtual bool childTypeAllowed(NodeType);
+ virtual String toString() const;
+};
+
+} //namespace
+
+#endif
diff --git a/WebCore/dom/DocumentFragment.idl b/WebCore/dom/DocumentFragment.idl
new file mode 100644
index 0000000..24af302
--- /dev/null
+++ b/WebCore/dom/DocumentFragment.idl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module core {
+
+ interface [
+ GenerateConstructor,
+ InterfaceUUID=F5C8DAF0-D728-4b2b-9D9C-630621B07D35,
+ ImplementationUUID=E57BF71F-3FAA-495c-A307-E288F8E5B2EC
+ ] DocumentFragment : EventTargetNode {
+ };
+
+}
diff --git a/WebCore/dom/DocumentMarker.h b/WebCore/dom/DocumentMarker.h
new file mode 100644
index 0000000..2ba9b47
--- /dev/null
+++ b/WebCore/dom/DocumentMarker.h
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the DOM implementation for WebCore.
+ *
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef DocumentMarker_h
+#define DocumentMarker_h
+
+#include "PlatformString.h"
+
+namespace WebCore {
+ class String;
+
+// A range of a node within a document that is "marked", such as the range of a misspelled word.
+// It optionally includes a description that could be displayed in the user interface.
+struct DocumentMarker {
+
+ enum MarkerType {
+ AllMarkers = -1,
+ Spelling,
+ Grammar,
+ TextMatch
+ };
+
+ MarkerType type;
+ unsigned startOffset;
+ unsigned endOffset;
+ String description;
+
+ bool operator==(const DocumentMarker& o) const
+ {
+ return type == o.type && startOffset == o.startOffset && endOffset == o.endOffset;
+ }
+
+ bool operator!=(const DocumentMarker& o) const
+ {
+ return !(*this == o);
+ }
+};
+
+} // namespace WebCore
+
+#endif // DocumentMarker_h
diff --git a/WebCore/dom/DocumentType.cpp b/WebCore/dom/DocumentType.cpp
new file mode 100644
index 0000000..f051363
--- /dev/null
+++ b/WebCore/dom/DocumentType.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "DocumentType.h"
+
+#include "DOMImplementation.h"
+#include "Document.h"
+#include "NamedNodeMap.h"
+
+namespace WebCore {
+
+DocumentType::DocumentType(DOMImplementation* i, Document* document, const String& n, const String& p, const String& s)
+ : Node(document)
+ , m_implementation(i)
+ , m_name(n)
+ , m_publicId(p)
+ , m_systemId(s)
+{
+}
+
+DocumentType::DocumentType(Document* document, const String& n, const String& p, const String& s)
+ : Node(document)
+ , m_name(n)
+ , m_publicId(p)
+ , m_systemId(s)
+{
+}
+
+DocumentType::DocumentType(Document* document, const DocumentType &t)
+ : Node(document)
+ , m_implementation(t.m_implementation)
+ , m_name(t.m_name)
+ , m_publicId(t.m_publicId)
+ , m_systemId(t.m_systemId)
+ , m_subset(t.m_subset)
+{
+}
+
+String DocumentType::toString() const
+{
+ if (m_name.isEmpty())
+ return "";
+
+ String result = "<!DOCTYPE ";
+ result += m_name;
+ if (!m_publicId.isEmpty()) {
+ result += " PUBLIC \"";
+ result += m_publicId;
+ result += "\"";
+ if (!m_systemId.isEmpty()) {
+ result += " \"";
+ result += m_systemId;
+ result += "\"";
+ }
+ } else if (!m_systemId.isEmpty()) {
+ result += " SYSTEM \"";
+ result += m_systemId;
+ result += "\"";
+ }
+ if (!m_subset.isEmpty()) {
+ result += " [";
+ result += m_subset;
+ result += "]";
+ }
+ result += ">";
+ return result;
+}
+
+KURL DocumentType::baseURI() const
+{
+ return KURL();
+}
+
+String DocumentType::nodeName() const
+{
+ return name();
+}
+
+Node::NodeType DocumentType::nodeType() const
+{
+ return DOCUMENT_TYPE_NODE;
+}
+
+PassRefPtr<Node> DocumentType::cloneNode(bool /*deep*/)
+{
+ return new DocumentType(document(), m_name, m_publicId, m_systemId);
+}
+
+void DocumentType::insertedIntoDocument()
+{
+ // Our document node can be null if we were created by a DOMImplementation. We use the parent() instead.
+ ASSERT(parent() && parent()->isDocumentNode());
+ if (parent() && parent()->isDocumentNode()) {
+ Document* doc = static_cast<Document*>(parent());
+ if (!doc->doctype())
+ doc->setDocType(this);
+ }
+ Node::insertedIntoDocument();
+}
+
+void DocumentType::removedFromDocument()
+{
+ if (document() && document()->doctype() == this)
+ document()->setDocType(0);
+ Node::removedFromDocument();
+}
+
+}
diff --git a/WebCore/dom/DocumentType.h b/WebCore/dom/DocumentType.h
new file mode 100644
index 0000000..c348c4c
--- /dev/null
+++ b/WebCore/dom/DocumentType.h
@@ -0,0 +1,77 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+#ifndef DocumentType_h
+#define DocumentType_h
+
+#include "Node.h"
+
+namespace WebCore {
+
+class NamedNodeMap;
+class DOMImplementation;
+
+class DocumentType : public Node
+{
+public:
+ DocumentType(DOMImplementation *, Document *, const String &name, const String &publicId, const String &systemId);
+ DocumentType(Document *, const String &name, const String &publicId, const String &systemId);
+ DocumentType(Document *, const DocumentType &);
+
+ // DOM methods & attributes for DocumentType
+ NamedNodeMap *entities() const { return m_entities.get(); }
+ NamedNodeMap *notations() const { return m_notations.get(); }
+
+ String name() const { return m_name; }
+ String publicId() const { return m_publicId; }
+ String systemId() const { return m_systemId; }
+ String internalSubset() const { return m_subset; }
+
+ virtual KURL baseURI() const;
+
+ // Other methods (not part of DOM)
+ DOMImplementation *implementation() const { return m_implementation.get(); }
+
+ virtual String nodeName() const;
+ virtual NodeType nodeType() const;
+ virtual PassRefPtr<Node> cloneNode(bool deep);
+ virtual String toString() const;
+
+ virtual void insertedIntoDocument();
+ virtual void removedFromDocument();
+
+private:
+ RefPtr<DOMImplementation> m_implementation;
+ RefPtr<NamedNodeMap> m_entities;
+ RefPtr<NamedNodeMap> m_notations;
+
+ String m_name;
+ String m_publicId;
+ String m_systemId;
+ String m_subset;
+};
+
+} //namespace
+
+#endif
diff --git a/WebCore/dom/DocumentType.idl b/WebCore/dom/DocumentType.idl
new file mode 100644
index 0000000..ef7b5b6
--- /dev/null
+++ b/WebCore/dom/DocumentType.idl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module core {
+
+ interface [
+ GenerateConstructor,
+ GenerateNativeConverter,
+ InterfaceUUID=20F04535-A423-4273-8CFE-3AD996100D29,
+ ImplementationUUID=736D952F-DBAF-458b-834B-F1638700BD88
+ ] DocumentType : Node {
+
+ // DOM Level 1
+
+ readonly attribute DOMString name;
+ readonly attribute NamedNodeMap entities;
+ readonly attribute NamedNodeMap notations;
+
+ // DOM Level 2
+
+ readonly attribute [ConvertNullStringTo=Null] DOMString publicId;
+ readonly attribute [ConvertNullStringTo=Null] DOMString systemId;
+ readonly attribute [ConvertNullStringTo=Null] DOMString internalSubset;
+
+ };
+
+}
diff --git a/WebCore/dom/DynamicNodeList.cpp b/WebCore/dom/DynamicNodeList.cpp
new file mode 100644
index 0000000..5a515d2
--- /dev/null
+++ b/WebCore/dom/DynamicNodeList.cpp
@@ -0,0 +1,183 @@
+/**
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "DynamicNodeList.h"
+
+#include "Document.h"
+#include "Element.h"
+
+namespace WebCore {
+
+DynamicNodeList::DynamicNodeList(PassRefPtr<Node> rootNode, bool needsNotifications)
+ : m_rootNode(rootNode)
+ , m_caches(new Caches)
+ , m_ownsCaches(true)
+ , m_needsNotifications(needsNotifications)
+{
+ m_rootNode->registerDynamicNodeList(this);
+}
+
+DynamicNodeList::DynamicNodeList(PassRefPtr<Node> rootNode, DynamicNodeList::Caches* info, bool needsNotifications)
+ : m_rootNode(rootNode)
+ , m_caches(info)
+ , m_ownsCaches(false)
+ , m_needsNotifications(needsNotifications)
+{
+ m_rootNode->registerDynamicNodeList(this);
+}
+
+DynamicNodeList::~DynamicNodeList()
+{
+ m_rootNode->unregisterDynamicNodeList(this);
+ if (m_ownsCaches)
+ delete m_caches;
+}
+
+unsigned DynamicNodeList::length() const
+{
+ if (m_caches->isLengthCacheValid)
+ return m_caches->cachedLength;
+
+ unsigned len = 0;
+
+ for (Node* n = m_rootNode->firstChild(); n; n = n->traverseNextNode(m_rootNode.get())) {
+ if (n->isElementNode()) {
+ if (nodeMatches(n))
+ len++;
+ }
+ }
+
+ m_caches->cachedLength = len;
+ m_caches->isLengthCacheValid = true;
+
+ return len;
+}
+
+Node* DynamicNodeList::itemForwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const
+{
+ ASSERT(remainingOffset >= 0);
+ for (Node* n = start; n; n = n->traverseNextNode(m_rootNode.get())) {
+ if (n->isElementNode()) {
+ if (nodeMatches(n)) {
+ if (!remainingOffset) {
+ m_caches->lastItem = n;
+ m_caches->lastItemOffset = offset;
+ m_caches->isItemCacheValid = true;
+ return n;
+ }
+ remainingOffset--;
+ }
+ }
+ }
+
+ return 0; // no matching node in this subtree
+}
+
+Node* DynamicNodeList::itemBackwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const
+{
+ ASSERT(remainingOffset < 0);
+ for (Node* n = start; n; n = n->traversePreviousNode(m_rootNode.get())) {
+ if (n->isElementNode()) {
+ if (nodeMatches(n)) {
+ if (!remainingOffset) {
+ m_caches->lastItem = n;
+ m_caches->lastItemOffset = offset;
+ m_caches->isItemCacheValid = true;
+ return n;
+ }
+ remainingOffset++;
+ }
+ }
+ }
+
+ return 0; // no matching node in this subtree
+}
+
+Node* DynamicNodeList::item(unsigned offset) const
+{
+ int remainingOffset = offset;
+ Node* start = m_rootNode->firstChild();
+ if (m_caches->isItemCacheValid) {
+ if (offset == m_caches->lastItemOffset)
+ return m_caches->lastItem;
+ else if (offset > m_caches->lastItemOffset || m_caches->lastItemOffset - offset < offset) {
+ start = m_caches->lastItem;
+ remainingOffset -= m_caches->lastItemOffset;
+ }
+ }
+
+ if (remainingOffset < 0)
+ return itemBackwardsFromCurrent(start, offset, remainingOffset);
+ return itemForwardsFromCurrent(start, offset, remainingOffset);
+}
+
+Node* DynamicNodeList::itemWithName(const AtomicString& elementId) const
+{
+ if (m_rootNode->isDocumentNode() || m_rootNode->inDocument()) {
+ Node* node = m_rootNode->document()->getElementById(elementId);
+
+ if (!node || !nodeMatches(node))
+ return 0;
+
+ for (Node* p = node->parentNode(); p; p = p->parentNode()) {
+ if (p == m_rootNode)
+ return node;
+ }
+
+ return 0;
+ }
+
+ unsigned l = length();
+ for (unsigned i = 0; i < l; i++) {
+ Node* node = item(i);
+ if (node->isElementNode() && static_cast<Element*>(node)->getIDAttribute() == elementId)
+ return node;
+ }
+
+ return 0;
+}
+
+void DynamicNodeList::rootNodeChildrenChanged()
+{
+ m_caches->reset();
+}
+
+void DynamicNodeList::rootNodeAttributeChanged()
+{
+}
+
+DynamicNodeList::Caches::Caches()
+ : lastItem(0)
+ , isLengthCacheValid(false)
+ , isItemCacheValid(false)
+{
+}
+
+void DynamicNodeList::Caches::reset()
+{
+ lastItem = 0;
+ isLengthCacheValid = false;
+ isItemCacheValid = false;
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/DynamicNodeList.h b/WebCore/dom/DynamicNodeList.h
new file mode 100644
index 0000000..58e50fd
--- /dev/null
+++ b/WebCore/dom/DynamicNodeList.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef DynamicNodeList_h
+#define DynamicNodeList_h
+
+#include "NodeList.h"
+#include <wtf/RefCounted.h>
+#include <wtf/Forward.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+ class AtomicString;
+ class Node;
+
+ class DynamicNodeList : public NodeList {
+ public:
+ struct Caches {
+ Caches();
+ void reset();
+
+ unsigned cachedLength;
+ Node* lastItem;
+ unsigned lastItemOffset;
+ bool isLengthCacheValid : 1;
+ bool isItemCacheValid : 1;
+ };
+
+ DynamicNodeList(PassRefPtr<Node> rootNode, bool needsNotifications);
+ DynamicNodeList(PassRefPtr<Node> rootNode, Caches*, bool needsNotifications);
+ virtual ~DynamicNodeList();
+
+ bool needsNotifications() const { return m_needsNotifications; }
+
+ // DOM methods & attributes for NodeList
+ virtual unsigned length() const;
+ virtual Node* item(unsigned index) const;
+ virtual Node* itemWithName(const AtomicString&) const;
+
+ // Other methods (not part of DOM)
+ virtual void rootNodeChildrenChanged();
+ virtual void rootNodeAttributeChanged();
+
+ protected:
+ virtual bool nodeMatches(Node*) const = 0;
+
+ RefPtr<Node> m_rootNode;
+ mutable Caches* m_caches;
+ bool m_ownsCaches;
+ bool m_needsNotifications;
+
+ private:
+ Node* itemForwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const;
+ Node* itemBackwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const;
+ };
+
+} // namespace WebCore
+
+#endif // DynamicNodeList_h
diff --git a/WebCore/dom/EditingText.cpp b/WebCore/dom/EditingText.cpp
new file mode 100644
index 0000000..59661e9
--- /dev/null
+++ b/WebCore/dom/EditingText.cpp
@@ -0,0 +1,52 @@
+/**
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "EditingText.h"
+
+// FIXME: does this really require a class? Perhaps any Text node
+// inside an editable element should have the "always create a renderer"
+// behavior.
+
+namespace WebCore {
+
+EditingText::EditingText(Document *impl, const String &text)
+ : Text(impl, text)
+{
+}
+
+EditingText::EditingText(Document *impl)
+ : Text(impl)
+{
+}
+
+EditingText::~EditingText()
+{
+}
+
+bool EditingText::rendererIsNeeded(RenderStyle *style)
+{
+ return true;
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/EditingText.h b/WebCore/dom/EditingText.h
new file mode 100644
index 0000000..3dcd8c1
--- /dev/null
+++ b/WebCore/dom/EditingText.h
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef EditingText_h
+#define EditingText_h
+
+#include "Text.h"
+
+namespace WebCore {
+
+class EditingText : public Text
+{
+public:
+ EditingText(Document *impl, const String &text);
+ EditingText(Document *impl);
+ virtual ~EditingText();
+
+ virtual bool rendererIsNeeded(RenderStyle *);
+};
+
+} // namespace WebCore
+
+#endif // EditingText_h
diff --git a/WebCore/dom/Element.cpp b/WebCore/dom/Element.cpp
new file mode 100644
index 0000000..8af84e2
--- /dev/null
+++ b/WebCore/dom/Element.cpp
@@ -0,0 +1,1230 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Peter Kelly (pmk@post.com)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * (C) 2007 David Smith (catfish.man@gmail.com)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * (C) 2007 Eric Seidel (eric@webkit.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "Element.h"
+
+#include "CSSStyleSelector.h"
+#include "CString.h"
+#include "ClassNames.h"
+#include "ClassNodeList.h"
+#include "Document.h"
+#include "Editor.h"
+#include "ExceptionCode.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "HTMLElement.h"
+#include "HTMLNames.h"
+#include "NamedAttrMap.h"
+#include "NodeList.h"
+#include "Page.h"
+#include "PlatformString.h"
+#include "RenderBlock.h"
+#include "SelectionController.h"
+#include "TextIterator.h"
+#include "XMLNames.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+using namespace XMLNames;
+
+class ElementRareData {
+public:
+ ElementRareData(Element*);
+ void resetComputedStyle(Element*);
+
+ IntSize m_minimumSizeForResizing;
+ RenderStyle* m_computedStyle;
+ bool m_needsFocusAppearanceUpdateSoonAfterAttach;
+};
+
+typedef HashMap<const Element*, ElementRareData*> ElementRareDataMap;
+
+static ElementRareDataMap& rareDataMap()
+{
+ static ElementRareDataMap* dataMap = new ElementRareDataMap;
+ return *dataMap;
+}
+
+static ElementRareData* rareDataFromMap(const Element* element)
+{
+ return rareDataMap().get(element);
+}
+
+static inline IntSize defaultMinimumSizeForResizing()
+{
+ return IntSize(INT_MAX, INT_MAX);
+}
+
+inline ElementRareData::ElementRareData(Element* element)
+ : m_minimumSizeForResizing(defaultMinimumSizeForResizing())
+ , m_computedStyle(0)
+ , m_needsFocusAppearanceUpdateSoonAfterAttach(false)
+{
+}
+
+void ElementRareData::resetComputedStyle(Element* element)
+{
+ if (!m_computedStyle)
+ return;
+ m_computedStyle->deref(element->document()->renderArena());
+ m_computedStyle = 0;
+}
+
+Element::Element(const QualifiedName& qName, Document *doc)
+ : ContainerNode(doc)
+ , m_tagName(qName)
+ , m_isStyleAttributeValid(true)
+ , m_synchronizingStyleAttribute(false)
+ , m_parsingChildrenFinished(true)
+{
+}
+
+Element::~Element()
+{
+ if (namedAttrMap)
+ namedAttrMap->detachFromElement();
+
+ if (!m_attrWasSpecifiedOrElementHasRareData)
+ ASSERT(!rareDataMap().contains(this));
+ else {
+ ElementRareDataMap& dataMap = rareDataMap();
+ ElementRareDataMap::iterator it = dataMap.find(this);
+ ASSERT(it != dataMap.end());
+ delete it->second;
+ dataMap.remove(it);
+ }
+}
+
+inline ElementRareData* Element::rareData()
+{
+ return m_attrWasSpecifiedOrElementHasRareData ? rareDataFromMap(this) : 0;
+}
+
+inline const ElementRareData* Element::rareData() const
+{
+ return m_attrWasSpecifiedOrElementHasRareData ? rareDataFromMap(this) : 0;
+}
+
+ElementRareData* Element::createRareData()
+{
+ if (m_attrWasSpecifiedOrElementHasRareData)
+ return rareDataMap().get(this);
+ ASSERT(!rareDataMap().contains(this));
+ ElementRareData* data = new ElementRareData(this);
+ rareDataMap().set(this, data);
+ m_attrWasSpecifiedOrElementHasRareData = true;
+ return data;
+}
+
+PassRefPtr<Node> Element::cloneNode(bool deep)
+{
+ ExceptionCode ec = 0;
+ RefPtr<Element> clone = document()->createElementNS(namespaceURI(), nodeName(), ec);
+ ASSERT(!ec);
+
+ // clone attributes
+ if (namedAttrMap)
+ *clone->attributes() = *namedAttrMap;
+
+ clone->copyNonAttributeProperties(this);
+
+ if (deep)
+ cloneChildNodes(clone.get());
+
+ return clone.release();
+}
+
+void Element::removeAttribute(const QualifiedName& name, ExceptionCode& ec)
+{
+ if (namedAttrMap) {
+ namedAttrMap->removeNamedItem(name, ec);
+ if (ec == NOT_FOUND_ERR)
+ ec = 0;
+ }
+}
+
+void Element::setAttribute(const QualifiedName& name, const String &value)
+{
+ ExceptionCode ec = 0;
+ setAttribute(name, value.impl(), ec);
+}
+
+void Element::setBooleanAttribute(const QualifiedName& name, bool b)
+{
+ if (b)
+ setAttribute(name, name.localName());
+ else {
+ ExceptionCode ex;
+ removeAttribute(name, ex);
+ }
+}
+
+// Virtual function, defined in base class.
+NamedAttrMap *Element::attributes() const
+{
+ return attributes(false);
+}
+
+NamedAttrMap* Element::attributes(bool readonly) const
+{
+ updateStyleAttributeIfNeeded();
+ if (!readonly && !namedAttrMap)
+ createAttributeMap();
+ return namedAttrMap.get();
+}
+
+Node::NodeType Element::nodeType() const
+{
+ return ELEMENT_NODE;
+}
+
+const ClassNames* Element::getClassNames() const
+{
+ return 0;
+}
+
+const AtomicString& Element::getIDAttribute() const
+{
+ return namedAttrMap ? namedAttrMap->id() : nullAtom;
+}
+
+bool Element::hasAttribute(const QualifiedName& name) const
+{
+ return hasAttributeNS(name.namespaceURI(), name.localName());
+}
+
+const AtomicString& Element::getAttribute(const QualifiedName& name) const
+{
+ if (name == styleAttr)
+ updateStyleAttributeIfNeeded();
+
+ if (namedAttrMap)
+ if (Attribute* a = namedAttrMap->getAttributeItem(name))
+ return a->value();
+
+ return nullAtom;
+}
+
+void Element::scrollIntoView(bool alignToTop)
+{
+ document()->updateLayoutIgnorePendingStylesheets();
+ IntRect bounds = getRect();
+ if (renderer()) {
+ // Align to the top / bottom and to the closest edge.
+ if (alignToTop)
+ renderer()->enclosingLayer()->scrollRectToVisible(bounds, RenderLayer::gAlignToEdgeIfNeeded, RenderLayer::gAlignTopAlways);
+ else
+ renderer()->enclosingLayer()->scrollRectToVisible(bounds, RenderLayer::gAlignToEdgeIfNeeded, RenderLayer::gAlignBottomAlways);
+ }
+}
+
+void Element::scrollIntoViewIfNeeded(bool centerIfNeeded)
+{
+ document()->updateLayoutIgnorePendingStylesheets();
+ IntRect bounds = getRect();
+ if (renderer()) {
+ if (centerIfNeeded)
+ renderer()->enclosingLayer()->scrollRectToVisible(bounds, RenderLayer::gAlignCenterIfNeeded, RenderLayer::gAlignCenterIfNeeded);
+ else
+ renderer()->enclosingLayer()->scrollRectToVisible(bounds, RenderLayer::gAlignToEdgeIfNeeded, RenderLayer::gAlignToEdgeIfNeeded);
+ }
+}
+
+void Element::scrollByUnits(int units, ScrollGranularity granularity)
+{
+ document()->updateLayoutIgnorePendingStylesheets();
+ if (RenderObject *rend = renderer()) {
+ if (rend->hasOverflowClip()) {
+ ScrollDirection direction = ScrollDown;
+ if (units < 0) {
+ direction = ScrollUp;
+ units = -units;
+ }
+ rend->layer()->scroll(direction, granularity, units);
+ }
+ }
+}
+
+void Element::scrollByLines(int lines)
+{
+ scrollByUnits(lines, ScrollByLine);
+}
+
+void Element::scrollByPages(int pages)
+{
+ scrollByUnits(pages, ScrollByPage);
+}
+
+int Element::offsetLeft()
+{
+ document()->updateLayoutIgnorePendingStylesheets();
+ if (RenderObject* rend = renderer())
+ return rend->offsetLeft();
+ return 0;
+}
+
+int Element::offsetTop()
+{
+ document()->updateLayoutIgnorePendingStylesheets();
+ if (RenderObject* rend = renderer())
+ return rend->offsetTop();
+ return 0;
+}
+
+int Element::offsetWidth()
+{
+ document()->updateLayoutIgnorePendingStylesheets();
+ if (RenderObject* rend = renderer())
+ return rend->offsetWidth();
+ return 0;
+}
+
+int Element::offsetHeight()
+{
+ document()->updateLayoutIgnorePendingStylesheets();
+ if (RenderObject* rend = renderer())
+ return rend->offsetHeight();
+ return 0;
+}
+
+Element* Element::offsetParent()
+{
+ document()->updateLayoutIgnorePendingStylesheets();
+ if (RenderObject* rend = renderer())
+ if (RenderObject* offsetParent = rend->offsetParent())
+ return static_cast<Element*>(offsetParent->element());
+ return 0;
+}
+
+int Element::clientLeft()
+{
+ document()->updateLayoutIgnorePendingStylesheets();
+
+ if (RenderObject* rend = renderer())
+ return rend->clientLeft();
+ return 0;
+}
+
+int Element::clientTop()
+{
+ document()->updateLayoutIgnorePendingStylesheets();
+
+ if (RenderObject* rend = renderer())
+ return rend->clientTop();
+ return 0;
+}
+
+int Element::clientWidth()
+{
+ document()->updateLayoutIgnorePendingStylesheets();
+
+ // When in strict mode, clientWidth for the document element should return the width of the containing frame.
+ // When in quirks mode, clientWidth for the body element should return the width of the containing frame.
+ bool inCompatMode = document()->inCompatMode();
+ if ((!inCompatMode && document()->documentElement() == this) ||
+ (inCompatMode && isHTMLElement() && document()->body() == this)) {
+ if (FrameView* view = document()->view())
+ return view->visibleWidth();
+ }
+
+
+ if (RenderObject* rend = renderer())
+ return rend->clientWidth();
+ return 0;
+}
+
+int Element::clientHeight()
+{
+ document()->updateLayoutIgnorePendingStylesheets();
+
+ // When in strict mode, clientHeight for the document element should return the height of the containing frame.
+ // When in quirks mode, clientHeight for the body element should return the height of the containing frame.
+ bool inCompatMode = document()->inCompatMode();
+
+ if ((!inCompatMode && document()->documentElement() == this) ||
+ (inCompatMode && isHTMLElement() && document()->body() == this)) {
+ if (FrameView* view = document()->view())
+ return view->visibleHeight();
+ }
+
+ if (RenderObject* rend = renderer())
+ return rend->clientHeight();
+ return 0;
+}
+
+int Element::scrollLeft()
+{
+ document()->updateLayoutIgnorePendingStylesheets();
+ if (RenderObject* rend = renderer())
+ return rend->scrollLeft();
+ return 0;
+}
+
+int Element::scrollTop()
+{
+ document()->updateLayoutIgnorePendingStylesheets();
+ if (RenderObject* rend = renderer())
+ return rend->scrollTop();
+ return 0;
+}
+
+void Element::setScrollLeft(int newLeft)
+{
+ document()->updateLayoutIgnorePendingStylesheets();
+ if (RenderObject *rend = renderer())
+ rend->setScrollLeft(newLeft);
+}
+
+void Element::setScrollTop(int newTop)
+{
+ document()->updateLayoutIgnorePendingStylesheets();
+ if (RenderObject *rend = renderer())
+ rend->setScrollTop(newTop);
+}
+
+int Element::scrollWidth()
+{
+ document()->updateLayoutIgnorePendingStylesheets();
+ if (RenderObject* rend = renderer())
+ return rend->scrollWidth();
+ return 0;
+}
+
+int Element::scrollHeight()
+{
+ document()->updateLayoutIgnorePendingStylesheets();
+ if (RenderObject* rend = renderer())
+ return rend->scrollHeight();
+ return 0;
+}
+
+static inline bool shouldIgnoreAttributeCase(const Element* e)
+{
+ return e && e->document()->isHTMLDocument() && e->isHTMLElement();
+}
+
+const AtomicString& Element::getAttribute(const String& name) const
+{
+ String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
+ if (localName == styleAttr.localName())
+ updateStyleAttributeIfNeeded();
+
+ if (namedAttrMap)
+ if (Attribute* a = namedAttrMap->getAttributeItem(localName))
+ return a->value();
+
+ return nullAtom;
+}
+
+const AtomicString& Element::getAttributeNS(const String& namespaceURI, const String& localName) const
+{
+ return getAttribute(QualifiedName(nullAtom, localName, namespaceURI));
+}
+
+void Element::setAttribute(const String& name, const String& value, ExceptionCode& ec)
+{
+ if (!Document::isValidName(name)) {
+ ec = INVALID_CHARACTER_ERR;
+ return;
+ }
+
+ String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
+
+ // allocate attributemap if necessary
+ Attribute* old = attributes(false)->getAttributeItem(localName);
+
+ // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly
+ if (namedAttrMap->isReadOnlyNode()) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return;
+ }
+
+ document()->incDOMTreeVersion();
+
+ if (localName == idAttr.localName())
+ updateId(old ? old->value() : nullAtom, value);
+
+ if (old && value.isNull())
+ namedAttrMap->removeAttribute(old->name());
+ else if (!old && !value.isNull())
+ namedAttrMap->addAttribute(createAttribute(QualifiedName(nullAtom, localName, nullAtom), value.impl()));
+ else if (old && !value.isNull()) {
+ old->setValue(value);
+ attributeChanged(old);
+ }
+}
+
+void Element::setAttribute(const QualifiedName& name, StringImpl* value, ExceptionCode& ec)
+{
+ document()->incDOMTreeVersion();
+
+ // allocate attributemap if necessary
+ Attribute* old = attributes(false)->getAttributeItem(name);
+
+ // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly
+ if (namedAttrMap->isReadOnlyNode()) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return;
+ }
+
+ if (name == idAttr)
+ updateId(old ? old->value() : nullAtom, value);
+
+ if (old && !value)
+ namedAttrMap->removeAttribute(name);
+ else if (!old && value)
+ namedAttrMap->addAttribute(createAttribute(name, value));
+ else if (old && value) {
+ old->setValue(value);
+ attributeChanged(old);
+ }
+}
+
+Attribute* Element::createAttribute(const QualifiedName& name, StringImpl* value)
+{
+ return new Attribute(name, value);
+}
+
+void Element::setAttributeMap(NamedAttrMap* list)
+{
+ document()->incDOMTreeVersion();
+
+ // If setting the whole map changes the id attribute, we need to call updateId.
+
+ Attribute *oldId = namedAttrMap ? namedAttrMap->getAttributeItem(idAttr) : 0;
+ Attribute *newId = list ? list->getAttributeItem(idAttr) : 0;
+
+ if (oldId || newId)
+ updateId(oldId ? oldId->value() : nullAtom, newId ? newId->value() : nullAtom);
+
+ if (namedAttrMap)
+ namedAttrMap->element = 0;
+
+ namedAttrMap = list;
+
+ if (namedAttrMap) {
+ namedAttrMap->element = this;
+ unsigned len = namedAttrMap->length();
+ for (unsigned i = 0; i < len; i++)
+ attributeChanged(namedAttrMap->attrs[i]);
+ // FIXME: What about attributes that were in the old map that are not in the new map?
+ }
+}
+
+bool Element::hasAttributes() const
+{
+ updateStyleAttributeIfNeeded();
+ return namedAttrMap && namedAttrMap->length() > 0;
+}
+
+String Element::nodeName() const
+{
+ return m_tagName.toString();
+}
+
+String Element::nodeNamePreservingCase() const
+{
+ return m_tagName.toString();
+}
+
+void Element::setPrefix(const AtomicString &_prefix, ExceptionCode& ec)
+{
+ ec = 0;
+ checkSetPrefix(_prefix, ec);
+ if (ec)
+ return;
+
+ m_tagName.setPrefix(_prefix);
+}
+
+KURL Element::baseURI() const
+{
+ KURL base(getAttribute(baseAttr));
+ if (!base.protocol().isEmpty())
+ return base;
+
+ Node* parent = parentNode();
+ if (!parent)
+ return base;
+
+ KURL parentBase = parent->baseURI();
+ if (parentBase.isNull())
+ return base;
+
+ return KURL(parentBase, base.string());
+}
+
+Node* Element::insertAdjacentElement(const String& where, Node* newChild, int& exception)
+{
+ if (!newChild) {
+ // IE throws COM Exception E_INVALIDARG; this is the best DOM exception alternative
+ exception = TYPE_MISMATCH_ERR;
+ return 0;
+ }
+
+ // In Internet Explorer if the element has no parent and where is "beforeBegin" or "afterEnd",
+ // a document fragment is created and the elements appended in the correct order. This document
+ // fragment isn't returned anywhere.
+ //
+ // This is impossible for us to implement as the DOM tree does not allow for such structures,
+ // Opera also appears to disallow such usage.
+
+ if (equalIgnoringCase(where, "beforeBegin")) {
+ if (Node* p = parent())
+ return p->insertBefore(newChild, this, exception) ? newChild : 0;
+ } else if (equalIgnoringCase(where, "afterBegin")) {
+ return insertBefore(newChild, firstChild(), exception) ? newChild : 0;
+ } else if (equalIgnoringCase(where, "beforeEnd")) {
+ return appendChild(newChild, exception) ? newChild : 0;
+ } else if (equalIgnoringCase(where, "afterEnd")) {
+ if (Node* p = parent())
+ return p->insertBefore(newChild, nextSibling(), exception) ? newChild : 0;
+ } else {
+ // IE throws COM Exception E_INVALIDARG; this is the best DOM exception alternative
+ exception = NOT_SUPPORTED_ERR;
+ }
+ return 0;
+}
+
+bool Element::contains(const Node* node) const
+{
+ if (!node)
+ return false;
+ return this == node || node->isDescendantOf(this);
+}
+
+void Element::createAttributeMap() const
+{
+ namedAttrMap = new NamedAttrMap(const_cast<Element*>(this));
+}
+
+bool Element::isURLAttribute(Attribute *attr) const
+{
+ return false;
+}
+
+const QualifiedName& Element::imageSourceAttributeName() const
+{
+ return srcAttr;
+}
+
+RenderStyle* Element::styleForRenderer(RenderObject* parentRenderer)
+{
+ return document()->styleSelector()->styleForElement(this);
+}
+
+RenderObject* Element::createRenderer(RenderArena* arena, RenderStyle* style)
+{
+ if (document()->documentElement() == this && style->display() == NONE) {
+ // Ignore display: none on root elements. Force a display of block in that case.
+ RenderBlock* result = new (arena) RenderBlock(this);
+ if (result)
+ result->setAnimatableStyle(style);
+ return result;
+ }
+ return RenderObject::createObject(this, style);
+}
+
+
+void Element::insertedIntoDocument()
+{
+ // need to do superclass processing first so inDocument() is true
+ // by the time we reach updateId
+ ContainerNode::insertedIntoDocument();
+
+ if (hasID()) {
+ NamedAttrMap* attrs = attributes(true);
+ if (attrs) {
+ Attribute* idItem = attrs->getAttributeItem(idAttr);
+ if (idItem && !idItem->isNull())
+ updateId(nullAtom, idItem->value());
+ }
+ }
+}
+
+void Element::removedFromDocument()
+{
+ if (hasID()) {
+ NamedAttrMap* attrs = attributes(true);
+ if (attrs) {
+ Attribute* idItem = attrs->getAttributeItem(idAttr);
+ if (idItem && !idItem->isNull())
+ updateId(idItem->value(), nullAtom);
+ }
+ }
+
+ ContainerNode::removedFromDocument();
+}
+
+void Element::attach()
+{
+ createRendererIfNeeded();
+ ContainerNode::attach();
+ if (ElementRareData* rd = rareData()) {
+ if (rd->m_needsFocusAppearanceUpdateSoonAfterAttach) {
+ if (isFocusable() && document()->focusedNode() == this)
+ document()->updateFocusAppearanceSoon();
+ rd->m_needsFocusAppearanceUpdateSoonAfterAttach = false;
+ }
+ }
+}
+
+void Element::detach()
+{
+ cancelFocusAppearanceUpdate();
+ if (ElementRareData* rd = rareData())
+ rd->resetComputedStyle(this);
+ ContainerNode::detach();
+}
+
+void Element::recalcStyle(StyleChange change)
+{
+ RenderStyle* currentStyle = renderStyle();
+ bool hasParentStyle = parentNode() ? parentNode()->renderStyle() : false;
+ bool hasPositionalRules = changed() && currentStyle && currentStyle->childrenAffectedByPositionalRules();
+
+#if ENABLE(SVG)
+ if (!hasParentStyle && isShadowNode() && isSVGElement())
+ hasParentStyle = true;
+#endif
+
+ if ((change > NoChange || changed())) {
+ if (ElementRareData* rd = rareData())
+ rd->resetComputedStyle(this);
+ }
+ if (hasParentStyle && (change >= Inherit || changed())) {
+ RenderStyle *newStyle = document()->styleSelector()->styleForElement(this);
+ StyleChange ch = diff(currentStyle, newStyle);
+ if (ch == Detach) {
+ if (attached())
+ detach();
+ // ### Suboptimal. Style gets calculated again.
+ attach();
+ // attach recalulates the style for all children. No need to do it twice.
+ setChanged(NoStyleChange);
+ setHasChangedChild(false);
+ newStyle->deref(document()->renderArena());
+ return;
+ }
+
+ if (currentStyle) {
+ // Preserve "affected by" bits that were propagated to us from descendants in the case where we didn't do a full
+ // style change (e.g., only inline style changed).
+ if (currentStyle->affectedByHoverRules())
+ newStyle->setAffectedByHoverRules(true);
+ if (currentStyle->affectedByActiveRules())
+ newStyle->setAffectedByActiveRules(true);
+ if (currentStyle->affectedByDragRules())
+ newStyle->setAffectedByDragRules(true);
+ if (currentStyle->childrenAffectedByForwardPositionalRules())
+ newStyle->setChildrenAffectedByForwardPositionalRules();
+ if (currentStyle->childrenAffectedByBackwardPositionalRules())
+ newStyle->setChildrenAffectedByBackwardPositionalRules();
+ if (currentStyle->childrenAffectedByFirstChildRules())
+ newStyle->setChildrenAffectedByFirstChildRules();
+ if (currentStyle->childrenAffectedByLastChildRules())
+ newStyle->setChildrenAffectedByLastChildRules();
+ if (currentStyle->childrenAffectedByDirectAdjacentRules())
+ newStyle->setChildrenAffectedByDirectAdjacentRules();
+ }
+
+ if (ch != NoChange)
+ setRenderStyle(newStyle);
+ else if (changed() && (document()->usesSiblingRules() || document()->usesDescendantRules())) {
+ // Although no change occurred, we use the new style so that the cousin style sharing code won't get
+ // fooled into believing this style is the same. This is only necessary if the document actually uses
+ // sibling/descendant rules, since otherwise it isn't possible for ancestor styles to affect sharing of
+ // descendants.
+ if (renderer())
+ renderer()->setStyleInternal(newStyle);
+ else
+ setRenderStyle(newStyle);
+ }
+
+ newStyle->deref(document()->renderArena());
+
+ if (change != Force) {
+ if ((document()->usesDescendantRules() || hasPositionalRules) && styleChangeType() == FullStyleChange)
+ change = Force;
+ else
+ change = ch;
+ }
+ }
+
+ for (Node *n = firstChild(); n; n = n->nextSibling()) {
+ if (change >= Inherit || n->isTextNode() || n->hasChangedChild() || n->changed())
+ n->recalcStyle(change);
+ }
+
+ setChanged(NoStyleChange);
+ setHasChangedChild(false);
+}
+
+bool Element::childTypeAllowed(NodeType type)
+{
+ switch (type) {
+ case ELEMENT_NODE:
+ case TEXT_NODE:
+ case COMMENT_NODE:
+ case PROCESSING_INSTRUCTION_NODE:
+ case CDATA_SECTION_NODE:
+ case ENTITY_REFERENCE_NODE:
+ return true;
+ break;
+ default:
+ return false;
+ }
+}
+
+static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback,
+ Node* beforeChange, Node* afterChange, int childCountDelta)
+{
+ if (!style || (e->changed() && style->childrenAffectedByPositionalRules()))
+ return;
+
+ // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time.
+ // In the DOM case, we only need to do something if |afterChange| is not 0.
+ // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
+ if (style->childrenAffectedByFirstChildRules() && afterChange) {
+ // Find our new first child.
+ Node* newFirstChild = 0;
+ for (newFirstChild = e->firstChild(); newFirstChild && !newFirstChild->isElementNode(); newFirstChild = newFirstChild->nextSibling()) {};
+
+ // Find the first element node following |afterChange|
+ Node* firstElementAfterInsertion = 0;
+ for (firstElementAfterInsertion = afterChange;
+ firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
+ firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
+
+ // This is the insert/append case.
+ if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertion && firstElementAfterInsertion->attached() &&
+ firstElementAfterInsertion->renderStyle() && firstElementAfterInsertion->renderStyle()->firstChildState())
+ firstElementAfterInsertion->setChanged();
+
+ // We also have to handle node removal.
+ if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && newFirstChild->renderStyle() && !newFirstChild->renderStyle()->firstChildState())
+ newFirstChild->setChanged();
+ }
+
+ // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time.
+ // In the DOM case, we only need to do something if |afterChange| is not 0.
+ if (style->childrenAffectedByLastChildRules() && beforeChange) {
+ // Find our new last child.
+ Node* newLastChild = 0;
+ for (newLastChild = e->lastChild(); newLastChild && !newLastChild->isElementNode(); newLastChild = newLastChild->previousSibling()) {};
+
+ // Find the last element node going backwards from |beforeChange|
+ Node* lastElementBeforeInsertion = 0;
+ for (lastElementBeforeInsertion = beforeChange;
+ lastElementBeforeInsertion && !lastElementBeforeInsertion->isElementNode();
+ lastElementBeforeInsertion = lastElementBeforeInsertion->previousSibling()) {};
+
+ if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertion && lastElementBeforeInsertion->attached() &&
+ lastElementBeforeInsertion->renderStyle() && lastElementBeforeInsertion->renderStyle()->lastChildState())
+ lastElementBeforeInsertion->setChanged();
+
+ // We also have to handle node removal. The parser callback case is similar to node removal as well in that we need to change the last child
+ // to match now.
+ if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && newLastChild->renderStyle() && !newLastChild->renderStyle()->lastChildState())
+ newLastChild->setChanged();
+ }
+
+ // The + selector. We need to invalidate the first element following the insertion point. It is the only possible element
+ // that could be affected by this DOM change.
+ if (style->childrenAffectedByDirectAdjacentRules() && afterChange) {
+ Node* firstElementAfterInsertion = 0;
+ for (firstElementAfterInsertion = afterChange;
+ firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
+ firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
+ if (firstElementAfterInsertion && firstElementAfterInsertion->attached())
+ firstElementAfterInsertion->setChanged();
+ }
+
+ // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type.
+ // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
+ // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
+ // backward case.
+ // |afterChange| is 0 in the parser callback case, so we won't do any work for the forward case if we don't have to.
+ // For performance reasons we just mark the parent node as changed, since we don't want to make childrenChanged O(n^2) by crawling all our kids
+ // here. recalcStyle will then force a walk of the children when it sees that this has happened.
+ if ((style->childrenAffectedByForwardPositionalRules() && afterChange) ||
+ (style->childrenAffectedByBackwardPositionalRules() && beforeChange))
+ e->setChanged();
+
+ // :empty selector.
+ if (style->affectedByEmpty() && (!style->emptyState() || e->hasChildNodes()))
+ e->setChanged();
+}
+
+void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
+{
+ ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
+ if (!changedByParser)
+ checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta);
+}
+
+void Element::finishParsingChildren()
+{
+ ContainerNode::finishParsingChildren();
+ m_parsingChildrenFinished = true;
+ checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0);
+}
+
+void Element::dispatchAttrRemovalEvent(Attribute*)
+{
+ ASSERT(!eventDispatchForbidden());
+#if 0
+ if (!document()->hasListenerType(Document::DOMATTRMODIFIED_LISTENER))
+ return;
+ ExceptionCode ec = 0;
+ dispatchEvent(new MutationEvent(DOMAttrModifiedEvent, true, false, attr, attr->value(),
+ attr->value(), document()->attrName(attr->id()), MutationEvent::REMOVAL), ec);
+#endif
+}
+
+void Element::dispatchAttrAdditionEvent(Attribute *attr)
+{
+ ASSERT(!eventDispatchForbidden());
+#if 0
+ if (!document()->hasListenerType(Document::DOMATTRMODIFIED_LISTENER))
+ return;
+ ExceptionCode ec = 0;
+ dispatchEvent(new MutationEvent(DOMAttrModifiedEvent, true, false, attr, attr->value(),
+ attr->value(),document()->attrName(attr->id()), MutationEvent::ADDITION), ec);
+#endif
+}
+
+String Element::openTagStartToString() const
+{
+ String result = "<" + nodeName();
+
+ NamedAttrMap *attrMap = attributes(true);
+
+ if (attrMap) {
+ unsigned numAttrs = attrMap->length();
+ for (unsigned i = 0; i < numAttrs; i++) {
+ result += " ";
+
+ Attribute *attribute = attrMap->attributeItem(i);
+ result += attribute->name().toString();
+ if (!attribute->value().isNull()) {
+ result += "=\"";
+ // FIXME: substitute entities for any instances of " or '
+ result += attribute->value();
+ result += "\"";
+ }
+ }
+ }
+
+ return result;
+}
+
+String Element::toString() const
+{
+ String result = openTagStartToString();
+
+ if (hasChildNodes()) {
+ result += ">";
+
+ for (Node *child = firstChild(); child != NULL; child = child->nextSibling()) {
+ result += child->toString();
+ }
+
+ result += "</";
+ result += nodeName();
+ result += ">";
+ } else {
+ result += " />";
+ }
+
+ return result;
+}
+
+void Element::updateId(const AtomicString& oldId, const AtomicString& newId)
+{
+ if (!inDocument())
+ return;
+
+ if (oldId == newId)
+ return;
+
+ Document* doc = document();
+ if (!oldId.isEmpty())
+ doc->removeElementById(oldId, this);
+ if (!newId.isEmpty())
+ doc->addElementById(newId, this);
+}
+
+#ifndef NDEBUG
+void Element::formatForDebugger(char* buffer, unsigned length) const
+{
+ String result;
+ String s;
+
+ s = nodeName();
+ if (s.length() > 0) {
+ result += s;
+ }
+
+ s = getAttribute(idAttr);
+ if (s.length() > 0) {
+ if (result.length() > 0)
+ result += "; ";
+ result += "id=";
+ result += s;
+ }
+
+ s = getAttribute(classAttr);
+ if (s.length() > 0) {
+ if (result.length() > 0)
+ result += "; ";
+ result += "class=";
+ result += s;
+ }
+
+ strncpy(buffer, result.utf8().data(), length - 1);
+}
+#endif
+
+PassRefPtr<Attr> Element::setAttributeNode(Attr *attr, ExceptionCode& ec)
+{
+ ASSERT(attr);
+ return static_pointer_cast<Attr>(attributes(false)->setNamedItem(attr, ec));
+}
+
+PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionCode& ec)
+{
+ ASSERT(attr);
+ return static_pointer_cast<Attr>(attributes(false)->setNamedItem(attr, ec));
+}
+
+PassRefPtr<Attr> Element::removeAttributeNode(Attr *attr, ExceptionCode& ec)
+{
+ if (!attr || attr->ownerElement() != this) {
+ ec = NOT_FOUND_ERR;
+ return 0;
+ }
+ if (document() != attr->document()) {
+ ec = WRONG_DOCUMENT_ERR;
+ return 0;
+ }
+
+ NamedAttrMap *attrs = attributes(true);
+ if (!attrs)
+ return 0;
+
+ return static_pointer_cast<Attr>(attrs->removeNamedItem(attr->qualifiedName(), ec));
+}
+
+void Element::setAttributeNS(const String& namespaceURI, const String& qualifiedName, const String& value, ExceptionCode& ec)
+{
+ String prefix, localName;
+ if (!Document::parseQualifiedName(qualifiedName, prefix, localName)) {
+ ec = INVALID_CHARACTER_ERR;
+ return;
+ }
+ setAttribute(QualifiedName(prefix, localName, namespaceURI), value.impl(), ec);
+}
+
+void Element::removeAttribute(const String& name, ExceptionCode& ec)
+{
+ String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
+
+ if (namedAttrMap) {
+ namedAttrMap->removeNamedItem(localName, ec);
+ if (ec == NOT_FOUND_ERR)
+ ec = 0;
+ }
+}
+
+void Element::removeAttributeNS(const String& namespaceURI, const String& localName, ExceptionCode& ec)
+{
+ removeAttribute(QualifiedName(nullAtom, localName, namespaceURI), ec);
+}
+
+PassRefPtr<Attr> Element::getAttributeNode(const String& name)
+{
+ NamedAttrMap* attrs = attributes(true);
+ if (!attrs)
+ return 0;
+ String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
+ return static_pointer_cast<Attr>(attrs->getNamedItem(localName));
+}
+
+PassRefPtr<Attr> Element::getAttributeNodeNS(const String& namespaceURI, const String& localName)
+{
+ NamedAttrMap* attrs = attributes(true);
+ if (!attrs)
+ return 0;
+ return static_pointer_cast<Attr>(attrs->getNamedItem(QualifiedName(nullAtom, localName, namespaceURI)));
+}
+
+bool Element::hasAttribute(const String& name) const
+{
+ NamedAttrMap* attrs = attributes(true);
+ if (!attrs)
+ return false;
+ String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
+ return attrs->getAttributeItem(localName);
+}
+
+bool Element::hasAttributeNS(const String& namespaceURI, const String& localName) const
+{
+ NamedAttrMap* attrs = attributes(true);
+ if (!attrs)
+ return false;
+ return attrs->getAttributeItem(QualifiedName(nullAtom, localName, namespaceURI));
+}
+
+CSSStyleDeclaration *Element::style()
+{
+ return 0;
+}
+
+void Element::focus(bool restorePreviousSelection)
+{
+ Document* doc = document();
+ if (doc->focusedNode() == this)
+ return;
+
+ doc->updateLayoutIgnorePendingStylesheets();
+
+ if (!supportsFocus())
+ return;
+
+ if (Page* page = doc->page())
+ page->focusController()->setFocusedNode(this, doc->frame());
+
+ if (!isFocusable()) {
+ createRareData()->m_needsFocusAppearanceUpdateSoonAfterAttach = true;
+ return;
+ }
+
+ cancelFocusAppearanceUpdate();
+ updateFocusAppearance(restorePreviousSelection);
+}
+
+void Element::updateFocusAppearance(bool restorePreviousSelection)
+{
+ if (this == rootEditableElement()) {
+ Frame* frame = document()->frame();
+ if (!frame)
+ return;
+
+ // FIXME: We should restore the previous selection if there is one.
+ Selection newSelection = hasTagName(htmlTag) || hasTagName(bodyTag) ? Selection(Position(this, 0), DOWNSTREAM) : Selection::selectionFromContentsOfNode(this);
+
+ if (frame->shouldChangeSelection(newSelection)) {
+ frame->selectionController()->setSelection(newSelection);
+ frame->revealSelection();
+ }
+ } else if (renderer() && !renderer()->isWidget())
+ renderer()->enclosingLayer()->scrollRectToVisible(getRect());
+}
+
+void Element::blur()
+{
+ cancelFocusAppearanceUpdate();
+ Document* doc = document();
+ if (doc->focusedNode() == this) {
+ if (doc->frame())
+ doc->frame()->page()->focusController()->setFocusedNode(0, doc->frame());
+ else
+ doc->setFocusedNode(0);
+ }
+}
+
+String Element::innerText() const
+{
+ // We need to update layout, since plainText uses line boxes in the render tree.
+ document()->updateLayoutIgnorePendingStylesheets();
+
+ if (!renderer())
+ return textContent(true);
+
+ return plainText(rangeOfContents(const_cast<Element*>(this)).get());
+}
+
+String Element::outerText() const
+{
+ // Getting outerText is the same as getting innerText, only
+ // setting is different. You would think this should get the plain
+ // text for the outer range, but this is wrong, <br> for instance
+ // would return different values for inner and outer text by such
+ // a rule, but it doesn't in WinIE, and we want to match that.
+ return innerText();
+}
+
+String Element::title() const
+{
+ return String();
+}
+
+IntSize Element::minimumSizeForResizing() const
+{
+ const ElementRareData* rd = rareData();
+ return rd ? rd->m_minimumSizeForResizing : defaultMinimumSizeForResizing();
+}
+
+void Element::setMinimumSizeForResizing(const IntSize& size)
+{
+ if (size == defaultMinimumSizeForResizing() && !rareData())
+ return;
+ createRareData()->m_minimumSizeForResizing = size;
+}
+
+RenderStyle* Element::computedStyle()
+{
+ if (RenderStyle* usedStyle = renderStyle())
+ return usedStyle;
+
+ if (!attached())
+ // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
+ // document tree and figure out when to destroy the computed style for such elements.
+ return 0;
+
+ ElementRareData* rd = createRareData();
+ if (!rd->m_computedStyle)
+ rd->m_computedStyle = document()->styleSelector()->styleForElement(this, parent() ? parent()->computedStyle() : 0);
+ return rd->m_computedStyle;
+}
+
+void Element::cancelFocusAppearanceUpdate()
+{
+ if (ElementRareData* rd = rareData())
+ rd->m_needsFocusAppearanceUpdateSoonAfterAttach = false;
+ if (document()->focusedNode() == this)
+ document()->cancelFocusAppearanceUpdate();
+}
+
+bool Element::virtualHasTagName(const QualifiedName& name) const
+{
+ return hasTagName(name);
+}
+
+}
diff --git a/WebCore/dom/Element.h b/WebCore/dom/Element.h
new file mode 100644
index 0000000..33727cd
--- /dev/null
+++ b/WebCore/dom/Element.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Peter Kelly (pmk@post.com)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Element_h
+#define Element_h
+
+#include "ContainerNode.h"
+#include "QualifiedName.h"
+#include "ScrollTypes.h"
+
+namespace WebCore {
+
+class Attr;
+class Attribute;
+class CSSStyleDeclaration;
+class ClassNames;
+class ElementRareData;
+class IntSize;
+
+class Element : public ContainerNode {
+public:
+ Element(const QualifiedName&, Document*);
+ ~Element();
+
+ // Used to quickly determine whether or not an element has a given CSS class.
+ virtual const ClassNames* getClassNames() const;
+ const AtomicString& getIDAttribute() const;
+ bool hasAttribute(const QualifiedName&) const;
+ const AtomicString& getAttribute(const QualifiedName&) const;
+ void setAttribute(const QualifiedName&, StringImpl* value, ExceptionCode&);
+ void removeAttribute(const QualifiedName&, ExceptionCode&);
+
+ bool hasAttributes() const;
+
+ bool hasAttribute(const String& name) const;
+ bool hasAttributeNS(const String& namespaceURI, const String& localName) const;
+
+ const AtomicString& getAttribute(const String& name) const;
+ const AtomicString& getAttributeNS(const String& namespaceURI, const String& localName) const;
+
+ void setAttribute(const String& name, const String& value, ExceptionCode&);
+ void setAttributeNS(const String& namespaceURI, const String& qualifiedName, const String& value, ExceptionCode&);
+
+ void scrollIntoView (bool alignToTop = true);
+ void scrollIntoViewIfNeeded(bool centerIfNeeded = true);
+
+ void scrollByUnits(int units, ScrollGranularity);
+ void scrollByLines(int lines);
+ void scrollByPages(int pages);
+
+ int offsetLeft();
+ int offsetTop();
+ int offsetWidth();
+ int offsetHeight();
+ Element* offsetParent();
+ int clientLeft();
+ int clientTop();
+ int clientWidth();
+ int clientHeight();
+ int scrollLeft();
+ int scrollTop();
+ void setScrollLeft(int);
+ void setScrollTop(int);
+ int scrollWidth();
+ int scrollHeight();
+
+ void removeAttribute(const String& name, ExceptionCode&);
+ void removeAttributeNS(const String& namespaceURI, const String& localName, ExceptionCode&);
+
+ PassRefPtr<Attr> getAttributeNode(const String& name);
+ PassRefPtr<Attr> getAttributeNodeNS(const String& namespaceURI, const String& localName);
+ PassRefPtr<Attr> setAttributeNode(Attr*, ExceptionCode&);
+ PassRefPtr<Attr> setAttributeNodeNS(Attr*, ExceptionCode&);
+ PassRefPtr<Attr> removeAttributeNode(Attr*, ExceptionCode&);
+
+ virtual CSSStyleDeclaration* style();
+
+ const QualifiedName& tagQName() const { return m_tagName; }
+ String tagName() const { return nodeName(); }
+ bool hasTagName(const QualifiedName& tagName) const { return m_tagName.matches(tagName); }
+
+ // A fast function for checking the local name against another atomic string.
+ bool hasLocalName(const AtomicString& other) const { return m_tagName.localName() == other; }
+ bool hasLocalName(const QualifiedName& other) const { return m_tagName.localName() == other.localName(); }
+
+ virtual const AtomicString& localName() const { return m_tagName.localName(); }
+ virtual const AtomicString& prefix() const { return m_tagName.prefix(); }
+ virtual void setPrefix(const AtomicString &_prefix, ExceptionCode&);
+ virtual const AtomicString& namespaceURI() const { return m_tagName.namespaceURI(); }
+
+ virtual KURL baseURI() const;
+
+ // DOM methods overridden from parent classes
+ virtual NodeType nodeType() const;
+ virtual PassRefPtr<Node> cloneNode(bool deep);
+ virtual String nodeName() const;
+ virtual bool isElementNode() const { return true; }
+ virtual void insertedIntoDocument();
+ virtual void removedFromDocument();
+ virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
+
+ virtual bool isInputTypeHidden() const { return false; }
+
+ String nodeNamePreservingCase() const;
+
+ // convenience methods which ignore exceptions
+ void setAttribute(const QualifiedName&, const String& value);
+ void setBooleanAttribute(const QualifiedName& name, bool);
+
+ virtual NamedAttrMap* attributes() const;
+ NamedAttrMap* attributes(bool readonly) const;
+
+ // This method is called whenever an attribute is added, changed or removed.
+ virtual void attributeChanged(Attribute*, bool preserveDecls = false) {}
+
+ // not part of the DOM
+ void setAttributeMap(NamedAttrMap*);
+
+ virtual void copyNonAttributeProperties(const Element* source) {}
+
+ virtual void attach();
+ virtual void detach();
+ virtual RenderStyle* styleForRenderer(RenderObject* parent);
+ virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+ virtual void recalcStyle(StyleChange = NoChange);
+
+ virtual RenderStyle* computedStyle();
+
+ virtual bool childTypeAllowed(NodeType);
+
+ virtual Attribute* createAttribute(const QualifiedName& name, StringImpl* value);
+
+ void dispatchAttrRemovalEvent(Attribute*);
+ void dispatchAttrAdditionEvent(Attribute*);
+
+ virtual void accessKeyAction(bool sendToAnyEvent) { }
+
+ virtual String toString() const;
+
+ virtual bool isURLAttribute(Attribute*) const;
+ virtual const QualifiedName& imageSourceAttributeName() const;
+ virtual String target() const { return String(); }
+
+ virtual void focus(bool restorePreviousSelection = true);
+ virtual void updateFocusAppearance(bool restorePreviousSelection);
+ void blur();
+
+#ifndef NDEBUG
+ virtual void formatForDebugger(char* buffer, unsigned length) const;
+#endif
+
+ Node* insertAdjacentElement(const String& where, Node* newChild, ExceptionCode&);
+ bool contains(const Node*) const;
+
+ String innerText() const;
+ String outerText() const;
+
+ virtual String title() const;
+
+ String openTagStartToString() const;
+
+ void updateId(const AtomicString& oldId, const AtomicString& newId);
+
+ IntSize minimumSizeForResizing() const;
+ void setMinimumSizeForResizing(const IntSize&);
+
+ // Use Document::registerForPageCacheCallbacks() to subscribe these
+ virtual void willSaveToCache() { }
+ virtual void didRestoreFromCache() { }
+
+ bool isFinishedParsingChildren() const { return m_parsingChildrenFinished; }
+ virtual void finishParsingChildren();
+ virtual void beginParsingChildren() { m_parsingChildrenFinished = false; }
+
+private:
+ ElementRareData* rareData();
+ const ElementRareData* rareData() const;
+ ElementRareData* createRareData();
+
+ virtual void createAttributeMap() const;
+
+ virtual void updateStyleAttributeIfNeeded() const {}
+
+ void updateFocusAppearanceSoonAfterAttach();
+ void cancelFocusAppearanceUpdate();
+
+ virtual bool virtualHasTagName(const QualifiedName&) const;
+
+private:
+ QualifiedName m_tagName;
+
+protected:
+ mutable RefPtr<NamedAttrMap> namedAttrMap;
+
+ // These two bits are really used by the StyledElement subclass, but they are pulled up here in order to be shared with other
+ // Element bits.
+ mutable bool m_isStyleAttributeValid : 1;
+ mutable bool m_synchronizingStyleAttribute : 1;
+
+private:
+ bool m_parsingChildrenFinished : 1;
+};
+
+} //namespace
+
+#endif
diff --git a/WebCore/dom/Element.idl b/WebCore/dom/Element.idl
new file mode 100644
index 0000000..31ff128
--- /dev/null
+++ b/WebCore/dom/Element.idl
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module core {
+
+ interface [
+ GenerateConstructor,
+ GenerateNativeConverter,
+ InterfaceUUID=FEFE9C21-E58C-4b5b-821A-61A514613763,
+ ImplementationUUID=12E5B08E-A680-4baf-9D1E-108AEF7ABBFB
+ ] Element : EventTargetNode {
+
+ // DOM Level 1 Core
+
+ readonly attribute [ConvertNullStringTo=Null] DOMString tagName;
+
+ [ConvertNullStringTo=Null] DOMString getAttribute(in DOMString name);
+ [OldStyleObjC, Custom] void setAttribute(in DOMString name,
+ in DOMString value)
+ raises(DOMException);
+ void removeAttribute(in DOMString name)
+ raises(DOMException);
+ Attr getAttributeNode(in DOMString name);
+ [Custom] Attr setAttributeNode(in Attr newAttr)
+ raises(DOMException);
+ Attr removeAttributeNode(in Attr oldAttr)
+ raises(DOMException);
+ NodeList getElementsByTagName(in DOMString name);
+
+ // DOM Level 2 Core
+
+ [OldStyleObjC] DOMString getAttributeNS(in [ConvertNullToNullString] DOMString namespaceURI,
+ in DOMString localName);
+ [OldStyleObjC, Custom] void setAttributeNS(in [ConvertNullToNullString] DOMString namespaceURI,
+ in DOMString qualifiedName,
+ in DOMString value)
+ raises(DOMException);
+ [OldStyleObjC] void removeAttributeNS(in [ConvertNullToNullString] DOMString namespaceURI,
+ in DOMString localName)
+ raises(DOMException);
+ [OldStyleObjC] NodeList getElementsByTagNameNS(in [ConvertNullToNullString] DOMString namespaceURI,
+ in DOMString localName);
+ [OldStyleObjC] Attr getAttributeNodeNS(in [ConvertNullToNullString] DOMString namespaceURI,
+ in DOMString localName);
+ [Custom] Attr setAttributeNodeNS(in Attr newAttr)
+ raises(DOMException);
+ boolean hasAttribute(in DOMString name);
+ [OldStyleObjC] boolean hasAttributeNS(in [ConvertNullToNullString] DOMString namespaceURI,
+ in DOMString localName);
+
+#if !defined(LANGUAGE_COM)
+ readonly attribute CSSStyleDeclaration style;
+#endif
+
+ // Common extensions
+
+ readonly attribute long offsetLeft;
+ readonly attribute long offsetTop;
+ readonly attribute long offsetWidth;
+ readonly attribute long offsetHeight;
+ readonly attribute Element offsetParent;
+ readonly attribute long clientLeft;
+ readonly attribute long clientTop;
+ readonly attribute long clientWidth;
+ readonly attribute long clientHeight;
+ attribute long scrollLeft;
+ attribute long scrollTop;
+ readonly attribute long scrollWidth;
+ readonly attribute long scrollHeight;
+
+ void focus();
+ void blur();
+ void scrollIntoView(in [Optional] boolean alignWithTop);
+
+ // IE extensions
+
+ Node insertAdjacentElement(in DOMString position,
+ in Node element)
+ raises(DOMException);
+ boolean contains(in Element element);
+
+ // WebKit extensions
+
+ void scrollIntoViewIfNeeded(in [Optional] boolean centerIfNeeded);
+ void scrollByLines(in long lines);
+ void scrollByPages(in long pages);
+
+ // HTML 5
+ NodeList getElementsByClassName(in DOMString name);
+
+ // ElementSelector - Selector API
+ Element querySelector(in [ConvertUndefinedOrNullToNullString] DOMString selectors)
+ raises(DOMException);
+ NodeList querySelectorAll(in [ConvertUndefinedOrNullToNullString] DOMString selectors)
+ raises(DOMException);
+
+#if defined(LANGUAGE_OBJECTIVE_C)
+ // Objective-C extensions
+ readonly attribute DOMString innerText;
+#endif
+
+ };
+
+}
diff --git a/WebCore/dom/Entity.cpp b/WebCore/dom/Entity.cpp
new file mode 100644
index 0000000..8e0db94
--- /dev/null
+++ b/WebCore/dom/Entity.cpp
@@ -0,0 +1,110 @@
+/**
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2000 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include "config.h"
+#include "Entity.h"
+
+namespace WebCore {
+
+Entity::Entity(Document* doc)
+ : ContainerNode(doc)
+{
+}
+
+Entity::Entity(Document* doc, const String& name)
+ : ContainerNode(doc)
+ , m_name(name)
+{
+}
+
+Entity::Entity(Document* doc, const String& publicId, const String& systemId, const String& notationName)
+ : ContainerNode(doc)
+ , m_publicId(publicId)
+ , m_systemId(systemId)
+ , m_notationName(notationName)
+{
+}
+
+String Entity::nodeName() const
+{
+ return m_name;
+}
+
+Node::NodeType Entity::nodeType() const
+{
+ return ENTITY_NODE;
+}
+
+PassRefPtr<Node> Entity::cloneNode(bool /*deep*/)
+{
+ // Spec says cloning Entity nodes is "implementation dependent". We do not support it.
+ return 0;
+}
+
+// DOM Section 1.1.1
+bool Entity::childTypeAllowed(NodeType type)
+{
+ switch (type) {
+ case ELEMENT_NODE:
+ case PROCESSING_INSTRUCTION_NODE:
+ case COMMENT_NODE:
+ case TEXT_NODE:
+ case CDATA_SECTION_NODE:
+ case ENTITY_REFERENCE_NODE:
+ return true;
+ break;
+ default:
+ return false;
+ }
+}
+
+String Entity::toString() const
+{
+ String result = "<!ENTITY' ";
+
+ if (!m_name.isEmpty()) {
+ result += " ";
+ result += m_name;
+ }
+
+ if (!m_publicId.isEmpty()) {
+ result += " PUBLIC \"";
+ result += m_publicId;
+ result += "\" \"";
+ result += m_systemId;
+ result += "\"";
+ } else if (!m_systemId.isEmpty()) {
+ result += " SYSTEM \"";
+ result += m_systemId;
+ result += "\"";
+ }
+
+ if (!m_notationName.isEmpty()) {
+ result += " NDATA ";
+ result += m_notationName;
+ }
+
+ result += ">";
+
+ return result;
+}
+
+} // namespace
diff --git a/WebCore/dom/Entity.h b/WebCore/dom/Entity.h
new file mode 100644
index 0000000..5c4297b
--- /dev/null
+++ b/WebCore/dom/Entity.h
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2000 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Entity_h
+#define Entity_h
+
+#include "ContainerNode.h"
+
+namespace WebCore {
+
+class Entity : public ContainerNode
+{
+public:
+ Entity(Document*);
+ Entity(Document*, const String& name);
+ Entity(Document*, const String& publicId, const String& systemId, const String& notationName);
+
+ // DOM methods & attributes for Entity
+ String publicId() const { return m_publicId; }
+ String systemId() const { return m_systemId; }
+ String notationName() const { return m_notationName; }
+
+ virtual String nodeName() const;
+ virtual NodeType nodeType() const;
+ virtual PassRefPtr<Node> cloneNode(bool deep);
+ virtual bool childTypeAllowed(NodeType);
+ virtual String toString() const;
+
+private:
+ String m_publicId;
+ String m_systemId;
+ String m_notationName;
+ String m_name;
+};
+
+} //namespace
+
+#endif
diff --git a/WebCore/dom/Entity.idl b/WebCore/dom/Entity.idl
new file mode 100644
index 0000000..b154797
--- /dev/null
+++ b/WebCore/dom/Entity.idl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module core {
+
+ interface [
+ GenerateConstructor,
+ InterfaceUUID=5CDB5ACA-F3A7-47ea-B89C-F335E4342C55,
+ ImplementationUUID=DDD2A621-59FD-4bb2-9F95-7061C3FB9F06
+ ] Entity : Node {
+ readonly attribute [ConvertNullStringTo=Null] DOMString publicId;
+ readonly attribute [ConvertNullStringTo=Null] DOMString systemId;
+ readonly attribute [ConvertNullStringTo=Null] DOMString notationName;
+ };
+
+}
diff --git a/WebCore/dom/EntityReference.cpp b/WebCore/dom/EntityReference.cpp
new file mode 100644
index 0000000..8f57519
--- /dev/null
+++ b/WebCore/dom/EntityReference.cpp
@@ -0,0 +1,84 @@
+/**
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2000 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include "config.h"
+#include "EntityReference.h"
+
+namespace WebCore {
+
+EntityReference::EntityReference(Document* doc)
+ : ContainerNode(doc)
+{
+}
+
+EntityReference::EntityReference(Document* doc, const String& entityName)
+ : ContainerNode(doc)
+ , m_entityName(entityName)
+{
+}
+
+String EntityReference::nodeName() const
+{
+ return m_entityName;
+}
+
+Node::NodeType EntityReference::nodeType() const
+{
+ return ENTITY_REFERENCE_NODE;
+}
+
+PassRefPtr<Node> EntityReference::cloneNode(bool deep)
+{
+ RefPtr<EntityReference> clone = new EntityReference(document(), m_entityName);
+ // ### make sure children are readonly
+ // ### since we are a reference, should we clone children anyway (even if not deep?)
+ if (deep)
+ cloneChildNodes(clone.get());
+ return clone.release();
+}
+
+// DOM Section 1.1.1
+bool EntityReference::childTypeAllowed(NodeType type)
+{
+ switch (type) {
+ case ELEMENT_NODE:
+ case PROCESSING_INSTRUCTION_NODE:
+ case COMMENT_NODE:
+ case TEXT_NODE:
+ case CDATA_SECTION_NODE:
+ case ENTITY_REFERENCE_NODE:
+ return true;
+ break;
+ default:
+ return false;
+ }
+}
+
+String EntityReference::toString() const
+{
+ String result = "&";
+ result += m_entityName;
+ result += ";";
+
+ return result;
+}
+
+} // namespace
diff --git a/WebCore/dom/EntityReference.h b/WebCore/dom/EntityReference.h
new file mode 100644
index 0000000..0536e6e
--- /dev/null
+++ b/WebCore/dom/EntityReference.h
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2000 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef EntityReference_h
+#define EntityReference_h
+
+#include "ContainerNode.h"
+
+namespace WebCore {
+
+class EntityReference : public ContainerNode
+{
+public:
+ EntityReference(Document*);
+ EntityReference(Document*, const String& entityName);
+
+ virtual String nodeName() const;
+ virtual NodeType nodeType() const;
+ virtual PassRefPtr<Node> cloneNode(bool deep);
+ virtual bool childTypeAllowed(NodeType);
+ virtual String toString() const;
+
+private:
+ String m_entityName;
+};
+
+} //namespace
+
+#endif
diff --git a/WebCore/dom/EntityReference.idl b/WebCore/dom/EntityReference.idl
new file mode 100644
index 0000000..8a206e9
--- /dev/null
+++ b/WebCore/dom/EntityReference.idl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module core {
+
+ interface [
+ GenerateConstructor,
+ InterfaceUUID=61BF4A03-19FB-4ac4-A624-5BF0893FDA65,
+ ImplementationUUID=486E1182-CF4F-450b-B411-A584CA42BBD0
+ ] EntityReference : Node {
+ };
+
+}
diff --git a/WebCore/dom/Event.cpp b/WebCore/dom/Event.cpp
new file mode 100644
index 0000000..543dfff
--- /dev/null
+++ b/WebCore/dom/Event.cpp
@@ -0,0 +1,174 @@
+/**
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2003, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include "config.h"
+#include "Event.h"
+
+#include "AtomicString.h"
+#include "SystemTime.h"
+
+namespace WebCore {
+
+Event::Event()
+ : RefCounted<Event>(0)
+ , m_canBubble(false)
+ , m_cancelable(false)
+ , m_propagationStopped(false)
+ , m_defaultPrevented(false)
+ , m_defaultHandled(false)
+ , m_cancelBubble(false)
+ , m_currentTarget(0)
+ , m_eventPhase(0)
+ , m_createTime(static_cast<DOMTimeStamp>(currentTime() * 1000.0))
+{
+}
+
+Event::Event(const AtomicString& eventType, bool canBubbleArg, bool cancelableArg)
+ : RefCounted<Event>(0)
+ , m_type(eventType)
+ , m_canBubble(canBubbleArg)
+ , m_cancelable(cancelableArg)
+ , m_propagationStopped(false)
+ , m_defaultPrevented(false)
+ , m_defaultHandled(false)
+ , m_cancelBubble(false)
+ , m_currentTarget(0)
+ , m_eventPhase(0)
+ , m_createTime(static_cast<DOMTimeStamp>(currentTime() * 1000.0))
+{
+}
+
+Event::~Event()
+{
+}
+
+void Event::initEvent(const AtomicString& eventTypeArg, bool canBubbleArg, bool cancelableArg)
+{
+ if (dispatched())
+ return;
+
+ m_type = eventTypeArg;
+ m_canBubble = canBubbleArg;
+ m_cancelable = cancelableArg;
+}
+
+bool Event::isUIEvent() const
+{
+ return false;
+}
+
+bool Event::isMouseEvent() const
+{
+ return false;
+}
+
+bool Event::isMutationEvent() const
+{
+ return false;
+}
+
+bool Event::isKeyboardEvent() const
+{
+ return false;
+}
+
+bool Event::isTextEvent() const
+{
+ return false;
+}
+
+bool Event::isDragEvent() const
+{
+ return false;
+}
+
+bool Event::isClipboardEvent() const
+{
+ return false;
+}
+
+bool Event::isWheelEvent() const
+{
+ return false;
+}
+
+#if ENABLE(CROSS_DOCUMENT_MESSAGING)
+bool Event::isMessageEvent() const
+{
+ return false;
+}
+#endif
+
+bool Event::isBeforeTextInsertedEvent() const
+{
+ return false;
+}
+
+bool Event::isOverflowEvent() const
+{
+ return false;
+}
+
+bool Event::isProgressEvent() const
+{
+ return false;
+}
+
+#if ENABLE(SVG)
+bool Event::isSVGZoomEvent() const
+{
+ return false;
+}
+#endif
+
+
+bool Event::storesResultAsString() const
+{
+ return false;
+}
+
+void Event::storeResult(const String&)
+{
+}
+
+void Event::setTarget(PassRefPtr<EventTarget> target)
+{
+ m_target = target;
+ if (m_target)
+ receivedTarget();
+}
+
+void Event::receivedTarget()
+{
+}
+
+void Event::setUnderlyingEvent(PassRefPtr<Event> ue)
+{
+ // Prohibit creation of a cycle -- just do nothing in that case.
+ for (Event* e = ue.get(); e; e = e->underlyingEvent())
+ if (e == this)
+ return;
+ m_underlyingEvent = ue;
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/Event.h b/WebCore/dom/Event.h
new file mode 100644
index 0000000..b74bc16
--- /dev/null
+++ b/WebCore/dom/Event.h
@@ -0,0 +1,159 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Event_h
+#define Event_h
+
+#include "AtomicString.h"
+#include "EventTarget.h"
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+ class Clipboard;
+
+ // FIXME: this should probably defined elsewhere.
+ typedef unsigned long long DOMTimeStamp;
+
+ class Event : public RefCounted<Event> {
+ public:
+ enum PhaseType {
+ CAPTURING_PHASE = 1,
+ AT_TARGET = 2,
+ BUBBLING_PHASE = 3
+ };
+
+ enum EventType {
+ MOUSEDOWN = 1,
+ MOUSEUP = 2,
+ MOUSEOVER = 4,
+ MOUSEOUT = 8,
+ MOUSEMOVE = 16,
+ MOUSEDRAG = 32,
+ CLICK = 64,
+ DBLCLICK = 128,
+ KEYDOWN = 256,
+ KEYUP = 512,
+ KEYPRESS = 1024,
+ DRAGDROP = 2048,
+ FOCUS = 4096,
+ BLUR = 8192,
+ SELECT = 16384,
+ CHANGE = 32768
+ };
+
+ Event();
+ Event(const AtomicString& type, bool canBubble, bool cancelable);
+ virtual ~Event();
+
+ void initEvent(const AtomicString& type, bool canBubble, bool cancelable);
+
+ const AtomicString& type() const { return m_type; }
+
+ EventTarget* target() const { return m_target.get(); }
+ void setTarget(PassRefPtr<EventTarget>);
+
+ EventTarget* currentTarget() const { return m_currentTarget; }
+ void setCurrentTarget(EventTarget* currentTarget) { m_currentTarget = currentTarget; }
+
+ unsigned short eventPhase() const { return m_eventPhase; }
+ void setEventPhase(unsigned short eventPhase) { m_eventPhase = eventPhase; }
+
+ bool bubbles() const { return m_canBubble; }
+ bool cancelable() const { return m_cancelable; }
+ DOMTimeStamp timeStamp() { return m_createTime; }
+ void stopPropagation() { m_propagationStopped = true; }
+
+ // IE Extensions
+ EventTarget* srcElement() const { return target(); } // MSIE extension - "the object that fired the event"
+
+ bool returnValue() const { return !defaultPrevented(); }
+ void setReturnValue(bool returnValue) { setDefaultPrevented(!returnValue); }
+
+ Clipboard* clipboardData() const { return isClipboardEvent() ? clipboard() : 0; }
+
+ virtual bool isUIEvent() const;
+ virtual bool isMouseEvent() const;
+ virtual bool isMutationEvent() const;
+ virtual bool isKeyboardEvent() const;
+ virtual bool isTextEvent() const;
+ virtual bool isDragEvent() const; // a subset of mouse events
+ virtual bool isClipboardEvent() const;
+#if ENABLE(CROSS_DOCUMENT_MESSAGING)
+ virtual bool isMessageEvent() const;
+#endif
+ virtual bool isWheelEvent() const;
+ virtual bool isBeforeTextInsertedEvent() const;
+ virtual bool isOverflowEvent() const;
+ virtual bool isProgressEvent() const;
+#if ENABLE(SVG)
+ virtual bool isSVGZoomEvent() const;
+#endif
+
+ bool propagationStopped() const { return m_propagationStopped; }
+
+ bool defaultPrevented() const { return m_defaultPrevented; }
+ void preventDefault() { if (m_cancelable) m_defaultPrevented = true; }
+ void setDefaultPrevented(bool defaultPrevented) { m_defaultPrevented = defaultPrevented; }
+
+ bool defaultHandled() const { return m_defaultHandled; }
+ void setDefaultHandled() { m_defaultHandled = true; }
+
+ bool cancelBubble() const { return m_cancelBubble; }
+ void setCancelBubble(bool cancel) { m_cancelBubble = cancel; }
+
+ Event* underlyingEvent() const { return m_underlyingEvent.get(); }
+ void setUnderlyingEvent(PassRefPtr<Event>);
+
+ virtual bool storesResultAsString() const;
+ virtual void storeResult(const String&);
+
+ virtual Clipboard* clipboard() const { return 0; }
+
+ protected:
+ virtual void receivedTarget();
+ bool dispatched() const { return m_target; }
+
+ private:
+ AtomicString m_type;
+ bool m_canBubble;
+ bool m_cancelable;
+
+ bool m_propagationStopped;
+ bool m_defaultPrevented;
+ bool m_defaultHandled;
+ bool m_cancelBubble;
+
+ EventTarget* m_currentTarget;
+ unsigned short m_eventPhase;
+ RefPtr<EventTarget> m_target;
+ DOMTimeStamp m_createTime;
+
+ RefPtr<Event> m_underlyingEvent;
+ };
+
+} // namespace WebCore
+
+#endif // Event_h
diff --git a/WebCore/dom/Event.idl b/WebCore/dom/Event.idl
new file mode 100644
index 0000000..ae394b9
--- /dev/null
+++ b/WebCore/dom/Event.idl
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module events {
+
+ // Introduced in DOM Level 2:
+ interface [
+ GenerateConstructor,
+ ObjCCustomInternalImpl,
+ InterfaceUUID=D17495FA-ACAD-4d27-9362-E19E057B189D,
+ ImplementationUUID=CFDCDDB2-5B3F-412d-BDA4-80B23C721549
+ ] Event {
+
+ // DOM PhaseType
+ const unsigned short CAPTURING_PHASE = 1;
+ const unsigned short AT_TARGET = 2;
+ const unsigned short BUBBLING_PHASE = 3;
+
+#if !defined(LANGUAGE_OBJECTIVE_C)
+ // Reverse-engineered from Netscape
+ const unsigned short MOUSEDOWN = 1;
+ const unsigned short MOUSEUP = 2;
+ const unsigned short MOUSEOVER = 4;
+ const unsigned short MOUSEOUT = 8;
+ const unsigned short MOUSEMOVE = 16;
+ const unsigned short MOUSEDRAG = 32;
+ const unsigned short CLICK = 64;
+ const unsigned short DBLCLICK = 128;
+ const unsigned short KEYDOWN = 256;
+ const unsigned short KEYUP = 512;
+ const unsigned short KEYPRESS = 1024;
+ const unsigned short DRAGDROP = 2048;
+ const unsigned short FOCUS = 4096;
+ const unsigned short BLUR = 8192;
+ const unsigned short SELECT = 16384;
+ const unsigned short CHANGE = 32768;
+#endif
+
+ readonly attribute DOMString type;
+ readonly attribute EventTarget target;
+ readonly attribute EventTarget currentTarget;
+ readonly attribute unsigned short eventPhase;
+ readonly attribute boolean bubbles;
+ readonly attribute boolean cancelable;
+#if !defined(LANGUAGE_COM)
+ readonly attribute DOMTimeStamp timeStamp;
+#endif
+ void stopPropagation();
+ void preventDefault();
+ [OldStyleObjC] void initEvent(in DOMString eventTypeArg,
+ in boolean canBubbleArg,
+ in boolean cancelableArg);
+
+ // IE Extensions
+ readonly attribute EventTarget srcElement;
+ attribute boolean returnValue;
+ attribute boolean cancelBubble;
+
+#if defined(LANGUAGE_JAVASCRIPT)
+ readonly attribute [Custom] Clipboard clipboardData;
+#endif
+
+ };
+
+}
diff --git a/WebCore/dom/EventException.h b/WebCore/dom/EventException.h
new file mode 100644
index 0000000..15a0dc8
--- /dev/null
+++ b/WebCore/dom/EventException.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2007 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 EventException_h
+#define EventException_h
+
+#include "ExceptionBase.h"
+
+namespace WebCore {
+
+ class EventException : public ExceptionBase {
+ public:
+ EventException(const ExceptionCodeDescription& description)
+ : ExceptionBase(description)
+ {
+ }
+
+ static const int EventExceptionOffset = 100;
+ static const int EventExceptionMax = 199;
+
+ enum EventExceptionCode {
+ UNSPECIFIED_EVENT_TYPE_ERR = EventExceptionOffset
+ };
+ };
+
+} // namespace WebCore
+
+#endif // EventException_h
diff --git a/WebCore/dom/EventException.idl b/WebCore/dom/EventException.idl
new file mode 100644
index 0000000..61cfd65
--- /dev/null
+++ b/WebCore/dom/EventException.idl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+module events {
+
+ // Introduced in DOM Level 2:
+ interface [
+ GenerateConstructor
+ ] EventException {
+
+ readonly attribute unsigned short code;
+ readonly attribute DOMString name;
+ readonly attribute DOMString message;
+
+#if defined(LANGUAGE_JAVASCRIPT)
+ // Override in a Mozilla compatible format
+ [DontEnum] DOMString toString();
+#endif
+
+ // EventExceptionCode
+ const unsigned short UNSPECIFIED_EVENT_TYPE_ERR = 0;
+
+ };
+
+}
diff --git a/WebCore/dom/EventListener.h b/WebCore/dom/EventListener.h
new file mode 100644
index 0000000..0938041
--- /dev/null
+++ b/WebCore/dom/EventListener.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef EventListener_h
+#define EventListener_h
+
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+ class Event;
+
+ class EventListener : public RefCounted<EventListener> {
+ public:
+ EventListener() : RefCounted<EventListener>(0) { }
+ virtual ~EventListener() { }
+ virtual void handleEvent(Event*, bool isWindowEvent = false) = 0;
+ virtual bool isHTMLEventListener() const { return false; }
+ };
+
+}
+
+#endif
diff --git a/WebCore/dom/EventListener.idl b/WebCore/dom/EventListener.idl
new file mode 100644
index 0000000..9d28703
--- /dev/null
+++ b/WebCore/dom/EventListener.idl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module events {
+
+ // Introduced in DOM Level 2:
+ interface [
+ ObjCProtocol,
+ InterfaceUUID=B04F2AE3-71E2-4ebe-ABFE-EF4938354082,
+ ImplementationUUID=DDFDD342-A78B-4f19-8F32-A5DF51B56E08
+ ] EventListener {
+ void handleEvent(in Event evt);
+ };
+
+}
diff --git a/WebCore/dom/EventNames.cpp b/WebCore/dom/EventNames.cpp
new file mode 100644
index 0000000..c5aaa37
--- /dev/null
+++ b/WebCore/dom/EventNames.cpp
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2005 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+
+#ifdef AVOID_STATIC_CONSTRUCTORS
+#define DOM_EVENT_NAMES_HIDE_GLOBALS 1
+#endif
+
+#include "EventNames.h"
+#include "StaticConstructors.h"
+
+namespace WebCore { namespace EventNames {
+
+#define DEFINE_EVENT_GLOBAL(name) \
+ DEFINE_GLOBAL(AtomicString, name##Event, #name)
+DOM_EVENT_NAMES_FOR_EACH(DEFINE_EVENT_GLOBAL)
+
+void init()
+{
+ static bool initialized;
+ if (!initialized) {
+ // Use placement new to initialize the globals.
+
+ AtomicString::init();
+ #define INITIALIZE_GLOBAL(name) new ((void*)&name##Event) AtomicString(#name);
+ DOM_EVENT_NAMES_FOR_EACH(INITIALIZE_GLOBAL)
+ initialized = true;
+ }
+}
+
+} }
diff --git a/WebCore/dom/EventNames.h b/WebCore/dom/EventNames.h
new file mode 100644
index 0000000..843fb16
--- /dev/null
+++ b/WebCore/dom/EventNames.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2005, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Jon Shier (jshier@iastate.edu)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef EventNames_h
+#define EventNames_h
+
+#include "AtomicString.h"
+
+namespace WebCore { namespace EventNames {
+
+#define DOM_EVENT_NAMES_FOR_EACH(macro) \
+ \
+ macro(abort) \
+ macro(beforecopy) \
+ macro(beforecut) \
+ macro(beforepaste) \
+ macro(beforeunload) \
+ macro(blur) \
+ macro(change) \
+ macro(click) \
+ macro(contextmenu) \
+ macro(copy) \
+ macro(cut) \
+ macro(dblclick) \
+ macro(drag) \
+ macro(dragend) \
+ macro(dragenter) \
+ macro(dragleave) \
+ macro(dragover) \
+ macro(dragstart) \
+ macro(drop) \
+ macro(error) \
+ macro(focus) \
+ macro(input) \
+ macro(keydown) \
+ macro(keypress) \
+ macro(keyup) \
+ macro(load) \
+ macro(message) \
+ macro(mousedown) \
+ macro(mousemove) \
+ macro(mouseout) \
+ macro(mouseover) \
+ macro(mouseup) \
+ macro(mousewheel) \
+ macro(overflowchanged) \
+ macro(paste) \
+ macro(readystatechange) \
+ macro(reset) \
+ macro(resize) \
+ macro(scroll) \
+ macro(search) \
+ macro(select) \
+ macro(selectstart) \
+ macro(submit) \
+ macro(textInput) \
+ macro(unload) \
+ macro(zoom) \
+ \
+ macro(DOMActivate) \
+ macro(DOMAttrModified) \
+ macro(DOMCharacterDataModified) \
+ macro(DOMFocusIn) \
+ macro(DOMFocusOut) \
+ macro(DOMNodeInserted) \
+ macro(DOMNodeInsertedIntoDocument) \
+ macro(DOMNodeRemoved) \
+ macro(DOMNodeRemovedFromDocument) \
+ macro(DOMSubtreeModified) \
+ macro(DOMContentLoaded) \
+ \
+ macro(webkitBeforeTextInserted) \
+ macro(webkitEditableContentChanged) \
+ \
+ macro(canshowcurrentframe) \
+ macro(canplay) \
+ macro(canplaythrough) \
+ macro(dataunavailable) \
+ macro(durationchange) \
+ macro(emptied) \
+ macro(ended) \
+ macro(loadedfirstframe) \
+ macro(loadedmetadata) \
+ macro(pause) \
+ macro(play) \
+ macro(ratechange) \
+ macro(timeupdate) \
+ macro(volumechange) \
+ macro(waiting) \
+ \
+ macro(begin) \
+ macro(progress) \
+ macro(stalled) \
+ \
+// end of DOM_EVENT_NAMES_FOR_EACH
+
+#ifndef DOM_EVENT_NAMES_HIDE_GLOBALS
+ #define DOM_EVENT_NAMES_DECLARE(name) extern const AtomicString name##Event;
+ DOM_EVENT_NAMES_FOR_EACH(DOM_EVENT_NAMES_DECLARE)
+ #undef DOM_EVENT_NAMES_DECLARE
+#endif
+
+ void init();
+
+} }
+
+#endif
diff --git a/WebCore/dom/EventTarget.cpp b/WebCore/dom/EventTarget.cpp
new file mode 100644
index 0000000..8eb8b9a
--- /dev/null
+++ b/WebCore/dom/EventTarget.cpp
@@ -0,0 +1,335 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
+ * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ *
+ */
+
+#include "config.h"
+#include "EventTarget.h"
+
+#include "Node.h"
+#include "NodeList.h"
+#include "Document.h"
+#include "Event.h"
+#include "EventListener.h"
+#include "EventNames.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "kjs_proxy.h"
+#include "RegisteredEventListener.h"
+
+namespace WebCore {
+
+using namespace EventNames;
+
+#ifndef NDEBUG
+static int gEventDispatchForbidden = 0;
+#endif
+
+EventTarget::~EventTarget()
+{
+}
+
+EventTargetNode* EventTarget::toNode()
+{
+ return 0;
+}
+
+XMLHttpRequest* EventTarget::toXMLHttpRequest()
+{
+ return 0;
+}
+
+#if ENABLE(SVG)
+SVGElementInstance* EventTarget::toSVGElementInstance()
+{
+ return 0;
+}
+#endif
+
+static inline void addListenerTypeToDocumentIfNeeded(const AtomicString& eventType, Document* document)
+{
+ Document::ListenerType type = static_cast<Document::ListenerType>(0);
+
+ if (eventType == DOMSubtreeModifiedEvent)
+ type = Document::DOMSUBTREEMODIFIED_LISTENER;
+ else if (eventType == DOMNodeInsertedEvent)
+ type = Document::DOMNODEINSERTED_LISTENER;
+ else if (eventType == DOMNodeRemovedEvent)
+ type = Document::DOMNODEREMOVED_LISTENER;
+ else if (eventType == DOMNodeRemovedFromDocumentEvent)
+ type = Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER;
+ else if (eventType == DOMNodeInsertedIntoDocumentEvent)
+ type = Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER;
+ else if (eventType == DOMAttrModifiedEvent)
+ type = Document::DOMATTRMODIFIED_LISTENER;
+ else if (eventType == DOMCharacterDataModifiedEvent)
+ type = Document::DOMCHARACTERDATAMODIFIED_LISTENER;
+ else if (eventType == overflowchangedEvent)
+ type = Document::OVERFLOWCHANGED_LISTENER;
+
+ if (type)
+ document->addListenerType(type);
+}
+
+void EventTarget::addEventListener(EventTargetNode* referenceNode, const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
+{
+ ASSERT(referenceNode);
+ if (!referenceNode->document()->attached())
+ return;
+
+ addListenerTypeToDocumentIfNeeded(eventType, referenceNode->document());
+
+ if (!referenceNode->m_regdListeners)
+ referenceNode->m_regdListeners = new RegisteredEventListenerList;
+
+ // Remove existing identical listener set with identical arguments.
+ // The DOM2 spec says that "duplicate instances are discarded" in this case.
+ removeEventListener(referenceNode, eventType, listener.get(), useCapture);
+
+ // adding the first one
+ if (referenceNode->m_regdListeners->isEmpty() && !referenceNode->inDocument())
+ referenceNode->document()->registerDisconnectedNodeWithEventListeners(referenceNode);
+
+ referenceNode->m_regdListeners->append(new RegisteredEventListener(eventType, listener.get(), useCapture));
+}
+
+void EventTarget::removeEventListener(EventTargetNode* referenceNode, const AtomicString& eventType, EventListener* listener, bool useCapture)
+{
+ ASSERT(referenceNode);
+ if (!referenceNode->m_regdListeners)
+ return;
+
+ RegisteredEventListener rl(eventType, listener, useCapture);
+
+ RegisteredEventListenerList::Iterator end = referenceNode->m_regdListeners->end();
+ for (RegisteredEventListenerList::Iterator it = referenceNode->m_regdListeners->begin(); it != end; ++it) {
+ if (*(*it).get() == rl) {
+ (*it)->setRemoved(true);
+ it = referenceNode->m_regdListeners->remove(it);
+
+ // removed last
+ if (referenceNode->m_regdListeners->isEmpty() && !referenceNode->inDocument())
+ referenceNode->document()->unregisterDisconnectedNodeWithEventListeners(referenceNode);
+
+ return;
+ }
+ }
+}
+
+bool EventTarget::dispatchGenericEvent(EventTargetNode* referenceNode, PassRefPtr<Event> e, ExceptionCode&, bool tempEvent)
+{
+ RefPtr<Event> evt(e);
+
+ ASSERT(!eventDispatchForbidden());
+ ASSERT(evt->target());
+ ASSERT(!evt->type().isNull()); // JavaScript code could create an event with an empty name
+
+ // work out what nodes to send event to
+ DeprecatedPtrList<Node> nodeChain;
+
+ if (referenceNode->inDocument()) {
+ for (Node* n = referenceNode; n; n = n->eventParentNode()) {
+ n->ref();
+ nodeChain.prepend(n);
+ }
+ } else {
+ // if node is not in the document just send event to itself
+ referenceNode->ref();
+ nodeChain.prepend(referenceNode);
+ }
+
+ DeprecatedPtrListIterator<Node> it(nodeChain);
+
+ // Before we begin dispatching events, give the target node a chance to do some work prior
+ // to the DOM event handlers getting a crack.
+ void* data = preDispatchEventHandler(evt.get());
+
+ // trigger any capturing event handlers on our way down
+ evt->setEventPhase(Event::CAPTURING_PHASE);
+ it.toFirst();
+
+ // Handle window events for capture phase, except load events, this quirk is needed
+ // because Mozilla used to never propagate load events to the window object
+ if (evt->type() != loadEvent && it.current()->isDocumentNode() && !evt->propagationStopped())
+ static_cast<Document*>(it.current())->handleWindowEvent(evt.get(), true);
+
+ EventTargetNode* eventTargetNode = 0;
+ for (; it.current() && it.current() != referenceNode && !evt->propagationStopped(); ++it) {
+ eventTargetNode = EventTargetNodeCast(it.current());
+ evt->setCurrentTarget(eventTargetRespectingSVGTargetRules(eventTargetNode));
+
+ eventTargetNode->handleLocalEvents(evt.get(), true);
+ }
+
+ // dispatch to the actual target node
+ it.toLast();
+
+ if (!evt->propagationStopped()) {
+ evt->setEventPhase(Event::AT_TARGET);
+
+ eventTargetNode = EventTargetNodeCast(it.current());
+ evt->setCurrentTarget(eventTargetRespectingSVGTargetRules(eventTargetNode));
+
+ // We do want capturing event listeners to be invoked here, even though
+ // that violates the specification since Mozilla does it.
+ eventTargetNode->handleLocalEvents(evt.get(), true);
+
+ eventTargetNode->handleLocalEvents(evt.get(), false);
+ }
+
+ --it;
+
+ // ok, now bubble up again (only non-capturing event handlers will be called)
+ // ### recalculate the node chain here? (e.g. if target node moved in document by previous event handlers)
+ // no. the DOM specs says:
+ // The chain of EventTargets from the event target to the top of the tree
+ // is determined before the initial dispatch of the event.
+ // If modifications occur to the tree during event processing,
+ // event flow will proceed based on the initial state of the tree.
+ //
+ // since the initial dispatch is before the capturing phase,
+ // there's no need to recalculate the node chain.
+ // (tobias)
+
+ if (evt->bubbles()) {
+ evt->setEventPhase(Event::BUBBLING_PHASE);
+
+ for (; it.current() && !evt->propagationStopped() && !evt->cancelBubble(); --it) {
+ eventTargetNode = EventTargetNodeCast(it.current());
+ evt->setCurrentTarget(eventTargetRespectingSVGTargetRules(eventTargetNode));
+
+ eventTargetNode->handleLocalEvents(evt.get(), false);
+ }
+
+ it.toFirst();
+
+ // Handle window events for bubbling phase, except load events, this quirk is needed
+ // because Mozilla used to never propagate load events at all
+ if (evt->type() != loadEvent && it.current()->isDocumentNode() && !evt->propagationStopped() && !evt->cancelBubble()) {
+ evt->setCurrentTarget(EventTargetNodeCast(it.current()));
+ static_cast<Document*>(it.current())->handleWindowEvent(evt.get(), false);
+ }
+ }
+
+ evt->setCurrentTarget(0);
+ evt->setEventPhase(0); // I guess this is correct, the spec does not seem to say
+ // anything about the default event handler phase.
+
+
+ // Now call the post dispatch.
+ postDispatchEventHandler(evt.get(), data);
+
+ // now we call all default event handlers (this is not part of DOM - it is internal to WebCore)
+ it.toLast();
+
+ if (evt->bubbles())
+ for (; it.current() && !evt->defaultPrevented() && !evt->defaultHandled(); --it)
+ EventTargetNodeCast(it.current())->defaultEventHandler(evt.get());
+ else if (!evt->defaultPrevented() && !evt->defaultHandled())
+ EventTargetNodeCast(it.current())->defaultEventHandler(evt.get());
+
+ // deref all nodes in chain
+ it.toFirst();
+ for (; it.current(); ++it)
+ it.current()->deref(); // this may delete us
+
+ Document::updateDocumentsRendering();
+
+ // If tempEvent is true, this means that the DOM implementation
+ // will not be storing a reference to the event, i.e. there is no
+ // way to retrieve it from javascript if a script does not already
+ // have a reference to it in a variable. So there is no need for
+ // the interpreter to keep the event in it's cache
+ Frame* frame = referenceNode->document()->frame();
+ if (tempEvent && frame && frame->scriptProxy()->isEnabled())
+ frame->scriptProxy()->finishedWithEvent(evt.get());
+
+ return !evt->defaultPrevented(); // ### what if defaultPrevented was called before dispatchEvent?
+}
+
+void EventTarget::removeAllEventListeners(EventTargetNode* referenceNode)
+{
+ delete referenceNode->m_regdListeners;
+ referenceNode->m_regdListeners = 0;
+}
+
+void EventTarget::insertedIntoDocument(EventTargetNode* referenceNode)
+{
+ if (referenceNode && referenceNode->m_regdListeners && !referenceNode->m_regdListeners->isEmpty())
+ referenceNode->document()->unregisterDisconnectedNodeWithEventListeners(referenceNode);
+}
+
+void EventTarget::removedFromDocument(EventTargetNode* referenceNode)
+{
+ if (referenceNode && referenceNode->m_regdListeners && !referenceNode->m_regdListeners->isEmpty())
+ referenceNode->document()->registerDisconnectedNodeWithEventListeners(referenceNode);
+}
+
+void EventTarget::handleLocalEvents(EventTargetNode* referenceNode, Event* evt, bool useCapture)
+{
+ ASSERT(referenceNode);
+ if (!referenceNode->m_regdListeners || referenceNode->m_regdListeners->isEmpty())
+ return;
+
+ RegisteredEventListenerList listenersCopy = *referenceNode->m_regdListeners;
+ RegisteredEventListenerList::Iterator end = listenersCopy.end();
+
+ for (RegisteredEventListenerList::Iterator it = listenersCopy.begin(); it != end; ++it) {
+ if ((*it)->eventType() == evt->type() && (*it)->useCapture() == useCapture && !(*it)->removed())
+ (*it)->listener()->handleEvent(evt, false);
+ }
+}
+
+EventTarget* EventTarget::eventTargetRespectingSVGTargetRules(EventTargetNode*& referenceNode)
+{
+ // TODO: SVG will add logic here soon.
+ return referenceNode;
+}
+
+#ifndef NDEBUG
+void forbidEventDispatch()
+{
+ ++gEventDispatchForbidden;
+}
+
+void allowEventDispatch()
+{
+ if (gEventDispatchForbidden > 0)
+ --gEventDispatchForbidden;
+}
+
+bool eventDispatchForbidden()
+{
+ return gEventDispatchForbidden > 0;
+}
+#endif // NDEBUG
+
+} // end namespace
diff --git a/WebCore/dom/EventTarget.h b/WebCore/dom/EventTarget.h
new file mode 100644
index 0000000..87e6810
--- /dev/null
+++ b/WebCore/dom/EventTarget.h
@@ -0,0 +1,116 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
+ * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 EventTarget_h
+#define EventTarget_h
+
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+ class AtomicString;
+ class Event;
+ class EventListener;
+ class EventTargetNode;
+ class RegisteredEventListener;
+ class SVGElementInstance;
+ class XMLHttpRequest;
+
+ typedef int ExceptionCode;
+
+ template<typename T> class DeprecatedValueList;
+ typedef DeprecatedValueList<RefPtr<RegisteredEventListener> > RegisteredEventListenerList;
+
+ class EventTarget {
+ public:
+ virtual EventTargetNode* toNode();
+ virtual XMLHttpRequest* toXMLHttpRequest();
+
+#if ENABLE(SVG)
+ virtual SVGElementInstance* toSVGElementInstance();
+#endif
+
+ virtual void addEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture) = 0;
+ virtual void removeEventListener(const AtomicString& eventType, EventListener*, bool useCapture) = 0;
+ virtual bool dispatchEvent(PassRefPtr<Event>, ExceptionCode&, bool tempEvent = false) = 0;
+
+ void ref() { refEventTarget(); }
+ void deref() { derefEventTarget(); }
+
+ // Handlers to do/undo actions on the target node before an event is dispatched to it and after the event
+ // has been dispatched. The data pointer is handed back by the preDispatch and passed to postDispatch.
+ virtual void* preDispatchEventHandler(Event*) { return 0; }
+ virtual void postDispatchEventHandler(Event*, void* dataFromPreDispatch) { }
+
+ protected:
+ virtual ~EventTarget();
+
+ void addEventListener(EventTargetNode* referenceNode, const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture);
+ void removeEventListener(EventTargetNode* referenceNode, const AtomicString& eventType, EventListener*, bool useCapture);
+
+ bool dispatchGenericEvent(EventTargetNode* referenceNode, PassRefPtr<Event>, ExceptionCode&, bool tempEvent);
+ void removeAllEventListeners(EventTargetNode* referenceNode);
+
+ void insertedIntoDocument(EventTargetNode* referenceNode);
+ void removedFromDocument(EventTargetNode* referenceNode);
+
+ void handleLocalEvents(EventTargetNode* referenceNode, Event*, bool useCapture);
+
+ // For non SVG elements it will return 'referenceNode' and not modify it.
+ // For SVG elements it eventually returns an event target not equal to 'referenceNode'.
+ //
+ // If 'referenceNode' is a child of a SVG <use> element it will return the corresponding SVGElementInstance
+ // as new event target - and 'referenceNode' will be set to the shadow tree element associated with
+ // the SVGElementInstance. Be sure to always dispatch/handle your events on this new event target.
+ EventTarget* eventTargetRespectingSVGTargetRules(EventTargetNode*& referenceNode);
+
+ private:
+ virtual void refEventTarget() = 0;
+ virtual void derefEventTarget() = 0;
+ };
+
+#ifndef NDEBUG
+
+void forbidEventDispatch();
+void allowEventDispatch();
+bool eventDispatchForbidden();
+
+#else
+
+inline void forbidEventDispatch() { }
+inline void allowEventDispatch() { }
+
+#endif // NDEBUG
+
+}
+#endif
diff --git a/WebCore/dom/EventTarget.idl b/WebCore/dom/EventTarget.idl
new file mode 100644
index 0000000..d3f46f7
--- /dev/null
+++ b/WebCore/dom/EventTarget.idl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module events {
+
+ // Introduced in DOM Level 2:
+ interface [
+ ObjCProtocol,
+ PureInterface,
+ InterfaceUUID=1D71C7EC-0BA0-4044-BDFD-56B3E8F5F9D4
+ ] EventTarget {
+ [OldStyleObjC, EventTargetNodeCast] void addEventListener(in DOMString type,
+ in EventListener listener,
+ in boolean useCapture);
+ [OldStyleObjC, EventTargetNodeCast] void removeEventListener(in DOMString type,
+ in EventListener listener,
+ in boolean useCapture);
+ [EventTargetNodeCast] boolean dispatchEvent(in Event event)
+ raises(EventException);
+ };
+
+}
diff --git a/WebCore/dom/EventTargetNode.cpp b/WebCore/dom/EventTargetNode.cpp
new file mode 100644
index 0000000..146ee8b
--- /dev/null
+++ b/WebCore/dom/EventTargetNode.cpp
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "EventTargetNode.h"
+
+#include "Document.h"
+#include "Event.h"
+#include "EventException.h"
+#include "EventHandler.h"
+#include "EventListener.h"
+#include "EventNames.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "KeyboardEvent.h"
+#include "MouseEvent.h"
+#include "MutationEvent.h"
+#include "Page.h"
+#include "PlatformMouseEvent.h"
+#include "PlatformWheelEvent.h"
+#include "ProgressEvent.h"
+#include "RegisteredEventListener.h"
+#include "TextEvent.h"
+#include "WheelEvent.h"
+
+namespace WebCore {
+
+using namespace EventNames;
+
+EventTargetNode::EventTargetNode(Document *doc)
+ : Node(doc)
+ , m_regdListeners(0)
+{
+}
+
+EventTargetNode::~EventTargetNode()
+{
+ if (m_regdListeners && !m_regdListeners->isEmpty() && !inDocument())
+ document()->unregisterDisconnectedNodeWithEventListeners(this);
+
+ delete m_regdListeners;
+ m_regdListeners = 0;
+}
+
+void EventTargetNode::insertedIntoDocument()
+{
+ EventTarget::insertedIntoDocument(this);
+ Node::insertedIntoDocument();
+}
+
+void EventTargetNode::removedFromDocument()
+{
+ EventTarget::removedFromDocument(this);
+ Node::removedFromDocument();
+}
+
+void EventTargetNode::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
+{
+ EventTarget::addEventListener(this, eventType, listener, useCapture);
+}
+
+void EventTargetNode::removeEventListener(const AtomicString& eventType, EventListener* listener, bool useCapture)
+{
+ EventTarget::removeEventListener(this, eventType, listener, useCapture);
+}
+
+void EventTargetNode::removeAllEventListeners()
+{
+ EventTarget::removeAllEventListeners(this);
+}
+
+void EventTargetNode::handleLocalEvents(Event *evt, bool useCapture)
+{
+ if (disabled() && evt->isMouseEvent())
+ return;
+
+ EventTarget::handleLocalEvents(this, evt, useCapture);
+}
+
+bool EventTargetNode::dispatchEvent(PassRefPtr<Event> e, ExceptionCode& ec, bool tempEvent)
+{
+ RefPtr<Event> evt(e);
+ ASSERT(!eventDispatchForbidden());
+ if (!evt || evt->type().isEmpty()) {
+ ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR;
+ return false;
+ }
+
+ EventTargetNode* eventTarget = this;
+ evt->setTarget(eventTargetRespectingSVGTargetRules(eventTarget));
+
+ RefPtr<FrameView> view = document()->view();
+ return dispatchGenericEvent(eventTarget, evt.release(), ec, tempEvent);
+}
+
+bool EventTargetNode::dispatchSubtreeModifiedEvent()
+{
+ ASSERT(!eventDispatchForbidden());
+
+ document()->incDOMTreeVersion();
+
+ notifyNodeListsAttributeChanged(); // FIXME: Can do better some day. Really only care about the name attribute changing.
+
+ if (!document()->hasListenerType(Document::DOMSUBTREEMODIFIED_LISTENER))
+ return false;
+ ExceptionCode ec = 0;
+ return dispatchEvent(new MutationEvent(DOMSubtreeModifiedEvent,
+ true,false,0,String(),String(),String(),0),ec,true);
+}
+
+void EventTargetNode::dispatchWindowEvent(const AtomicString &eventType, bool canBubbleArg, bool cancelableArg)
+{
+ ASSERT(!eventDispatchForbidden());
+ ExceptionCode ec = 0;
+ RefPtr<Event> evt = new Event(eventType, canBubbleArg, cancelableArg);
+ RefPtr<Document> doc = document();
+ evt->setTarget(doc);
+ doc->handleWindowEvent(evt.get(), true);
+ doc->handleWindowEvent(evt.get(), false);
+
+ if (eventType == loadEvent) {
+ // For onload events, send a separate load event to the enclosing frame only.
+ // This is a DOM extension and is independent of bubbling/capturing rules of
+ // the DOM.
+ Element* ownerElement = doc->ownerElement();
+ if (ownerElement) {
+ RefPtr<Event> ownerEvent = new Event(eventType, false, cancelableArg);
+ ownerEvent->setTarget(ownerElement);
+ ownerElement->dispatchGenericEvent(ownerElement, ownerEvent.release(), ec, true);
+ }
+ }
+}
+
+bool EventTargetNode::dispatchUIEvent(const AtomicString& eventType, int detail, PassRefPtr<Event> underlyingEvent)
+{
+ ASSERT(!eventDispatchForbidden());
+ ASSERT(eventType == DOMFocusInEvent || eventType == DOMFocusOutEvent || eventType == DOMActivateEvent);
+
+ bool cancelable = eventType == DOMActivateEvent;
+
+ ExceptionCode ec = 0;
+ RefPtr<UIEvent> evt = new UIEvent(eventType, true, cancelable, document()->defaultView(), detail);
+ evt->setUnderlyingEvent(underlyingEvent);
+ return dispatchEvent(evt.release(), ec, true);
+}
+
+bool EventTargetNode::dispatchKeyEvent(const PlatformKeyboardEvent& key)
+{
+ ASSERT(!eventDispatchForbidden());
+ ExceptionCode ec = 0;
+ RefPtr<KeyboardEvent> keyboardEvent = new KeyboardEvent(key, document()->defaultView());
+ bool r = dispatchEvent(keyboardEvent,ec,true);
+
+ // we want to return false if default is prevented (already taken care of)
+ // or if the element is default-handled by the DOM. Otherwise we let it just
+ // let it get handled by AppKit
+ if (keyboardEvent->defaultHandled())
+ r = false;
+
+ return r;
+}
+
+bool EventTargetNode::dispatchMouseEvent(const PlatformMouseEvent& event, const AtomicString& eventType,
+ int detail, Node* relatedTarget)
+{
+ ASSERT(!eventDispatchForbidden());
+
+ IntPoint contentsPos;
+ if (FrameView* view = document()->view())
+ contentsPos = view->windowToContents(event.pos());
+
+ short button = event.button();
+
+ ASSERT(event.eventType() == MouseEventMoved || button != NoButton);
+
+ return dispatchMouseEvent(eventType, button, detail,
+ contentsPos.x(), contentsPos.y(), event.globalX(), event.globalY(),
+ event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(),
+ false, relatedTarget);
+}
+
+void EventTargetNode::dispatchSimulatedMouseEvent(const AtomicString& eventType,
+ PassRefPtr<Event> underlyingEvent)
+{
+ ASSERT(!eventDispatchForbidden());
+
+ if (m_dispatchingSimulatedEvent)
+ return;
+
+ bool ctrlKey = false;
+ bool altKey = false;
+ bool shiftKey = false;
+ bool metaKey = false;
+ if (UIEventWithKeyState* keyStateEvent = findEventWithKeyState(underlyingEvent.get())) {
+ ctrlKey = keyStateEvent->ctrlKey();
+ altKey = keyStateEvent->altKey();
+ shiftKey = keyStateEvent->shiftKey();
+ metaKey = keyStateEvent->metaKey();
+ }
+
+ m_dispatchingSimulatedEvent = true;
+
+ // Like Gecko, we just pass 0 for everything when we make a fake mouse event.
+ // Internet Explorer instead gives the current mouse position and state.
+ dispatchMouseEvent(eventType, 0, 0, 0, 0, 0, 0,
+ ctrlKey, altKey, shiftKey, metaKey, true, 0, underlyingEvent);
+
+ m_dispatchingSimulatedEvent = false;
+}
+
+void EventTargetNode::dispatchSimulatedClick(PassRefPtr<Event> event, bool sendMouseEvents, bool showPressedLook)
+{
+ if (m_dispatchingSimulatedEvent)
+ return;
+
+ // send mousedown and mouseup before the click, if requested
+ if (sendMouseEvents)
+ dispatchSimulatedMouseEvent(mousedownEvent, event.get());
+ setActive(true, showPressedLook);
+ if (sendMouseEvents)
+ dispatchSimulatedMouseEvent(mouseupEvent, event.get());
+ setActive(false);
+
+ // always send click
+ dispatchSimulatedMouseEvent(clickEvent, event);
+}
+
+bool EventTargetNode::dispatchMouseEvent(const AtomicString& eventType, int button, int detail,
+ int pageX, int pageY, int screenX, int screenY,
+ bool ctrlKey, bool altKey, bool shiftKey, bool metaKey,
+ bool isSimulated, Node* relatedTargetArg, PassRefPtr<Event> underlyingEvent)
+{
+ ASSERT(!eventDispatchForbidden());
+ if (disabled()) // Don't even send DOM events for disabled controls..
+ return true;
+
+ if (eventType.isEmpty())
+ return false; // Shouldn't happen.
+
+ // Dispatching the first event can easily result in this node being destroyed.
+ // Since we dispatch up to three events here, we need to make sure we're referenced
+ // so the pointer will be good for the two subsequent ones.
+ RefPtr<Node> protect(this);
+
+ bool cancelable = eventType != mousemoveEvent;
+
+ ExceptionCode ec = 0;
+
+ bool swallowEvent = false;
+
+ // Attempting to dispatch with a non-EventTarget relatedTarget causes the relatedTarget to be silently ignored.
+ RefPtr<EventTargetNode> relatedTarget = (relatedTargetArg && relatedTargetArg->isEventTargetNode())
+ ? static_cast<EventTargetNode*>(relatedTargetArg) : 0;
+
+ RefPtr<Event> mouseEvent = new MouseEvent(eventType,
+ true, cancelable, document()->defaultView(),
+ detail, screenX, screenY, pageX, pageY,
+ ctrlKey, altKey, shiftKey, metaKey, button,
+ relatedTarget.get(), 0, isSimulated);
+ mouseEvent->setUnderlyingEvent(underlyingEvent.get());
+
+ dispatchEvent(mouseEvent, ec, true);
+ bool defaultHandled = mouseEvent->defaultHandled();
+ bool defaultPrevented = mouseEvent->defaultPrevented();
+ if (defaultHandled || defaultPrevented)
+ swallowEvent = true;
+
+ // Special case: If it's a double click event, we also send the dblclick event. This is not part
+ // of the DOM specs, but is used for compatibility with the ondblclick="" attribute. This is treated
+ // as a separate event in other DOM-compliant browsers like Firefox, and so we do the same.
+ if (eventType == clickEvent && detail == 2) {
+ RefPtr<Event> doubleClickEvent = new MouseEvent(dblclickEvent,
+ true, cancelable, document()->defaultView(),
+ detail, screenX, screenY, pageX, pageY,
+ ctrlKey, altKey, shiftKey, metaKey, button,
+ relatedTarget.get(), 0, isSimulated);
+ doubleClickEvent->setUnderlyingEvent(underlyingEvent.get());
+ if (defaultHandled)
+ doubleClickEvent->setDefaultHandled();
+ dispatchEvent(doubleClickEvent, ec, true);
+ if (doubleClickEvent->defaultHandled() || doubleClickEvent->defaultPrevented())
+ swallowEvent = true;
+ }
+
+ return swallowEvent;
+}
+
+void EventTargetNode::dispatchWheelEvent(PlatformWheelEvent& e)
+{
+ ASSERT(!eventDispatchForbidden());
+ if (e.deltaX() == 0 && e.deltaY() == 0)
+ return;
+
+ FrameView* view = document()->view();
+ if (!view)
+ return;
+
+ IntPoint pos = view->windowToContents(e.pos());
+
+ RefPtr<WheelEvent> we = new WheelEvent(e.deltaX(), e.deltaY(),
+ document()->defaultView(), e.globalX(), e.globalY(), pos.x(), pos.y(),
+ e.ctrlKey(), e.altKey(), e.shiftKey(), e.metaKey());
+ ExceptionCode ec = 0;
+ if (!dispatchEvent(we, ec, true))
+ e.accept();
+}
+
+
+void EventTargetNode::dispatchFocusEvent()
+{
+ dispatchHTMLEvent(focusEvent, false, false);
+}
+
+void EventTargetNode::dispatchBlurEvent()
+{
+ dispatchHTMLEvent(blurEvent, false, false);
+}
+
+bool EventTargetNode::dispatchHTMLEvent(const AtomicString &eventType, bool canBubbleArg, bool cancelableArg)
+{
+ ASSERT(!eventDispatchForbidden());
+ ExceptionCode ec = 0;
+ return dispatchEvent(new Event(eventType, canBubbleArg, cancelableArg), ec, true);
+}
+
+bool EventTargetNode::dispatchProgressEvent(const AtomicString &eventType, bool lengthComputableArg, unsigned loadedArg, unsigned totalArg)
+{
+ ASSERT(!eventDispatchForbidden());
+ ExceptionCode ec = 0;
+ return dispatchEvent(new ProgressEvent(eventType, lengthComputableArg, loadedArg, totalArg), ec, true);
+}
+
+void EventTargetNode::removeHTMLEventListener(const AtomicString &eventType)
+{
+ if (!m_regdListeners) // nothing to remove
+ return;
+
+ RegisteredEventListenerList::Iterator end = m_regdListeners->end();
+ for (RegisteredEventListenerList::Iterator it = m_regdListeners->begin(); it != end; ++it)
+ if ((*it)->eventType() == eventType && (*it)->listener()->isHTMLEventListener()) {
+ it = m_regdListeners->remove(it);
+ // removed last
+ if (m_regdListeners->isEmpty() && !inDocument())
+ document()->unregisterDisconnectedNodeWithEventListeners(this);
+ return;
+ }
+}
+
+void EventTargetNode::setHTMLEventListener(const AtomicString &eventType, PassRefPtr<EventListener> listener)
+{
+ // In case we are the only one holding a reference to it, we don't want removeHTMLEventListener to destroy it.
+ removeHTMLEventListener(eventType);
+ if (listener)
+ addEventListener(eventType, listener.get(), false);
+}
+
+EventListener *EventTargetNode::getHTMLEventListener(const AtomicString &eventType)
+{
+ if (!m_regdListeners)
+ return 0;
+
+ RegisteredEventListenerList::Iterator end = m_regdListeners->end();
+ for (RegisteredEventListenerList::Iterator it = m_regdListeners->begin(); it != end; ++it)
+ if ((*it)->eventType() == eventType && (*it)->listener()->isHTMLEventListener())
+ return (*it)->listener();
+ return 0;
+}
+
+bool EventTargetNode::disabled() const
+{
+ return false;
+}
+
+void EventTargetNode::defaultEventHandler(Event* event)
+{
+ if (event->target() != this)
+ return;
+ const AtomicString& eventType = event->type();
+ if (eventType == keydownEvent || eventType == keypressEvent) {
+ if (event->isKeyboardEvent())
+ if (Frame* frame = document()->frame())
+ frame->eventHandler()->defaultKeyboardEventHandler(static_cast<KeyboardEvent*>(event));
+ } else if (eventType == clickEvent) {
+ int detail = event->isUIEvent() ? static_cast<UIEvent*>(event)->detail() : 0;
+ dispatchUIEvent(DOMActivateEvent, detail, event);
+ } else if (eventType == contextmenuEvent) {
+ if (Frame* frame = document()->frame())
+ if (Page* page = frame->page())
+ page->contextMenuController()->handleContextMenuEvent(event);
+ } else if (eventType == textInputEvent) {
+ if (event->isTextEvent())
+ if (Frame* frame = document()->frame())
+ frame->eventHandler()->defaultTextInputEventHandler(static_cast<TextEvent*>(event));
+ }
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/EventTargetNode.h b/WebCore/dom/EventTargetNode.h
new file mode 100644
index 0000000..9a0647b
--- /dev/null
+++ b/WebCore/dom/EventTargetNode.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef EventTargetNode_h
+#define EventTargetNode_h
+
+#include "EventTarget.h"
+#include "Node.h"
+
+namespace WebCore {
+
+class EventTargetNode : public Node,
+ public EventTarget {
+public:
+ EventTargetNode(Document*);
+ virtual ~EventTargetNode();
+
+ virtual bool isEventTargetNode() const { return true; }
+ virtual EventTargetNode* toNode() { return this; }
+
+ virtual void addEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture);
+ virtual void removeEventListener(const AtomicString& eventType, EventListener*, bool useCapture);
+ virtual bool dispatchEvent(PassRefPtr<Event>, ExceptionCode&, bool tempEvent = false);
+ void removeAllEventListeners();
+
+ void setHTMLEventListener(const AtomicString& eventType, PassRefPtr<EventListener>);
+ void removeHTMLEventListener(const AtomicString& eventType);
+ bool dispatchHTMLEvent(const AtomicString& eventType, bool canBubble, bool cancelable);
+ EventListener* getHTMLEventListener(const AtomicString& eventType);
+
+ bool dispatchSubtreeModifiedEvent();
+ void dispatchWindowEvent(const AtomicString& eventType, bool canBubble, bool cancelable);
+ bool dispatchUIEvent(const AtomicString& eventType, int detail = 0, PassRefPtr<Event> underlyingEvent = 0);
+ bool dispatchKeyEvent(const PlatformKeyboardEvent&);
+ void dispatchWheelEvent(PlatformWheelEvent&);
+ bool dispatchMouseEvent(const PlatformMouseEvent&, const AtomicString& eventType,
+ int clickCount = 0, Node* relatedTarget = 0);
+ bool dispatchMouseEvent(const AtomicString& eventType, int button, int clickCount,
+ int pageX, int pageY, int screenX, int screenY,
+ bool ctrlKey, bool altKey, bool shiftKey, bool metaKey,
+ bool isSimulated = false, Node* relatedTarget = 0, PassRefPtr<Event> underlyingEvent = 0);
+ void dispatchSimulatedMouseEvent(const AtomicString& eventType, PassRefPtr<Event> underlyingEvent = 0);
+ void dispatchSimulatedClick(PassRefPtr<Event> underlyingEvent, bool sendMouseEvents = false, bool showPressedLook = true);
+ bool dispatchProgressEvent(const AtomicString &eventType, bool lengthComputableArg, unsigned loadedArg, unsigned totalArg);
+
+ virtual void handleLocalEvents(Event*, bool useCapture);
+
+ virtual void dispatchFocusEvent();
+ virtual void dispatchBlurEvent();
+
+ virtual void insertedIntoDocument();
+ virtual void removedFromDocument();
+
+ /**
+ * Perform the default action for an event e.g. submitting a form
+ */
+ virtual void defaultEventHandler(Event*);
+
+ /**
+ * Used for disabled form elements; if true, prevents mouse events from being dispatched
+ * to event listeners, and prevents DOMActivate events from being sent at all.
+ */
+ virtual bool disabled() const;
+
+ RegisteredEventListenerList* localEventListeners() const { return m_regdListeners; }
+
+ using Node::ref;
+ using Node::deref;
+
+protected:
+ friend class EventTarget;
+ RegisteredEventListenerList* m_regdListeners;
+
+private:
+ virtual void refEventTarget() { ref(); }
+ virtual void derefEventTarget() { deref(); }
+};
+
+inline EventTargetNode* EventTargetNodeCast(Node* n)
+{
+ ASSERT(n->isEventTargetNode());
+ return static_cast<EventTargetNode*>(n);
+}
+
+inline const EventTargetNode* EventTargetNodeCast(const Node* n)
+{
+ ASSERT(n->isEventTargetNode());
+ return static_cast<const EventTargetNode*>(n);
+}
+
+} // namespace WebCore
+
+#endif // EventTargetNode_h
diff --git a/WebCore/dom/ExceptionBase.cpp b/WebCore/dom/ExceptionBase.cpp
new file mode 100644
index 0000000..d2526bd
--- /dev/null
+++ b/WebCore/dom/ExceptionBase.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "ExceptionBase.h"
+
+namespace WebCore {
+
+ExceptionBase::ExceptionBase(const ExceptionCodeDescription& description)
+ : RefCounted<ExceptionBase>(0)
+{
+ m_code = description.code;
+ if (description.name) {
+ m_name = description.name;
+ m_message = String::format("%s: %s Exception %d", description.name, description.typeName, description.code);
+ } else
+ m_message = String::format("%s Exception %d", description.typeName, description.code);
+}
+
+String ExceptionBase::toString() const
+{
+ return "Error: " + m_message;
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/ExceptionBase.h b/WebCore/dom/ExceptionBase.h
new file mode 100644
index 0000000..3fe14ae
--- /dev/null
+++ b/WebCore/dom/ExceptionBase.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2007 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 ExceptionBase_h
+#define ExceptionBase_h
+
+#include "ExceptionCode.h"
+#include "PlatformString.h"
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+ class ExceptionBase : public RefCounted<ExceptionBase> {
+ public:
+ ExceptionBase(const ExceptionCodeDescription&);
+
+ unsigned short code() const { return m_code; }
+ String name() const { return m_name; }
+ String message() const { return m_message; }
+
+ String toString() const;
+
+ private:
+ unsigned short m_code;
+ String m_name;
+ String m_message;
+ };
+
+} // namespace WebCore
+
+#endif // ExceptionBase_h
diff --git a/WebCore/dom/ExceptionCode.cpp b/WebCore/dom/ExceptionCode.cpp
new file mode 100644
index 0000000..e7ee20d
--- /dev/null
+++ b/WebCore/dom/ExceptionCode.cpp
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2006, 2007 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "ExceptionCode.h"
+
+#include "EventException.h"
+#include "RangeException.h"
+#include "XMLHttpRequestException.h"
+
+#if ENABLE(SVG)
+#include "SVGException.h"
+#endif
+
+#if ENABLE(XPATH)
+#include "XPathException.h"
+#endif
+
+namespace WebCore {
+
+static const char* const exceptionNames[] = {
+ "INDEX_SIZE_ERR",
+ "DOMSTRING_SIZE_ERR",
+ "HIERARCHY_REQUEST_ERR",
+ "WRONG_DOCUMENT_ERR",
+ "INVALID_CHARACTER_ERR",
+ "NO_DATA_ALLOWED_ERR",
+ "NO_MODIFICATION_ALLOWED_ERR",
+ "NOT_FOUND_ERR",
+ "NOT_SUPPORTED_ERR",
+ "INUSE_ATTRIBUTE_ERR",
+ "INVALID_STATE_ERR",
+ "SYNTAX_ERR",
+ "INVALID_MODIFICATION_ERR",
+ "NAMESPACE_ERR",
+ "INVALID_ACCESS_ERR",
+ "VALIDATION_ERR",
+ "TYPE_MISMATCH_ERR"
+};
+
+static const char* const rangeExceptionNames[] = {
+ "BAD_BOUNDARYPOINTS_ERR",
+ "INVALID_NODE_TYPE_ERR"
+};
+
+static const char* const eventExceptionNames[] = {
+ "UNSPECIFIED_EVENT_TYPE_ERR"
+};
+
+static const char* const xmlHttpRequestExceptionNames[] = {
+ "NETWORK_ERR"
+};
+
+#if ENABLE(XPATH)
+static const char* const xpathExceptionNames[] = {
+ "INVALID_EXPRESSION_ERR",
+ "TYPE_ERR"
+};
+#endif
+
+#if ENABLE(SVG)
+static const char* const svgExceptionNames[] = {
+ "SVG_WRONG_TYPE_ERR",
+ "SVG_INVALID_VALUE_ERR",
+ "SVG_MATRIX_NOT_INVERTABLE"
+};
+#endif
+
+void getExceptionCodeDescription(ExceptionCode ec, ExceptionCodeDescription& description)
+{
+ ASSERT(ec);
+
+ const char* typeName;
+ int code = ec;
+ const char* const* nameTable;
+ int nameTableSize;
+ int nameTableOffset;
+ ExceptionType type;
+
+ if (code >= RangeException::RangeExceptionOffset && code <= RangeException::RangeExceptionMax) {
+ type = RangeExceptionType;
+ typeName = "DOM Range";
+ code -= RangeException::RangeExceptionOffset;
+ nameTable = rangeExceptionNames;
+ nameTableSize = sizeof(rangeExceptionNames) / sizeof(rangeExceptionNames[0]);
+ nameTableOffset = RangeException::BAD_BOUNDARYPOINTS_ERR;
+ } else if (code >= EventException::EventExceptionOffset && code <= EventException::EventExceptionMax) {
+ type = EventExceptionType;
+ typeName = "DOM Events";
+ code -= EventException::EventExceptionOffset;
+ nameTable = eventExceptionNames;
+ nameTableSize = sizeof(eventExceptionNames) / sizeof(eventExceptionNames[0]);
+ nameTableOffset = EventException::UNSPECIFIED_EVENT_TYPE_ERR;
+ } else if (code >= XMLHttpRequestException::XMLHttpRequestExceptionOffset && code <= XMLHttpRequestException::XMLHttpRequestExceptionMax) {
+ type = XMLHttpRequestExceptionType;
+ typeName = "XMLHttpRequest";
+ code -= XMLHttpRequestException::XMLHttpRequestExceptionOffset;
+ nameTable = xmlHttpRequestExceptionNames;
+ nameTableSize = sizeof(xmlHttpRequestExceptionNames) / sizeof(xmlHttpRequestExceptionNames[0]);
+ // XMLHttpRequest exception codes start with 101 and we don't want 100 empty elements in the name array
+ nameTableOffset = XMLHttpRequestException::NETWORK_ERR;
+#if ENABLE(XPATH)
+ } else if (code >= XPathException::XPathExceptionOffset && code <= XPathException::XPathExceptionMax) {
+ type = XPathExceptionType;
+ typeName = "DOM XPath";
+ code -= XPathException::XPathExceptionOffset;
+ nameTable = xpathExceptionNames;
+ nameTableSize = sizeof(xpathExceptionNames) / sizeof(xpathExceptionNames[0]);
+ // XPath exception codes start with 51 and we don't want 51 empty elements in the name array
+ nameTableOffset = XPathException::INVALID_EXPRESSION_ERR;
+#endif
+#if ENABLE(SVG)
+ } else if (code >= SVGException::SVGExceptionOffset && code <= SVGException::SVGExceptionMax) {
+ type = SVGExceptionType;
+ typeName = "DOM SVG";
+ code -= SVGException::SVGExceptionOffset;
+ nameTable = svgExceptionNames;
+ nameTableSize = sizeof(svgExceptionNames) / sizeof(svgExceptionNames[0]);
+ nameTableOffset = SVGException::SVG_WRONG_TYPE_ERR;
+#endif
+ } else {
+ type = DOMExceptionType;
+ typeName = "DOM";
+ nameTable = exceptionNames;
+ nameTableSize = sizeof(exceptionNames) / sizeof(exceptionNames[0]);
+ nameTableOffset = INDEX_SIZE_ERR;
+ }
+
+ description.typeName = typeName;
+ description.name = (ec >= nameTableOffset && ec - nameTableOffset < nameTableSize) ? nameTable[ec - nameTableOffset] : 0;
+ description.code = code;
+ description.type = type;
+
+ // All exceptions used in the DOM code should have names.
+ ASSERT(description.name);
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/ExceptionCode.h b/WebCore/dom/ExceptionCode.h
new file mode 100644
index 0000000..7e75587
--- /dev/null
+++ b/WebCore/dom/ExceptionCode.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef ExceptionCode_h
+#define ExceptionCode_h
+
+namespace WebCore {
+
+ // The DOM standards use unsigned short for exception codes.
+ // In our DOM implementation we use int instead, and use different
+ // numerical ranges for different types of DOM exception, so that
+ // an exception of any type can be expressed with a single integer.
+ typedef int ExceptionCode;
+
+ enum {
+ INDEX_SIZE_ERR = 1,
+ DOMSTRING_SIZE_ERR = 2,
+ HIERARCHY_REQUEST_ERR = 3,
+ WRONG_DOCUMENT_ERR = 4,
+ INVALID_CHARACTER_ERR = 5,
+ NO_DATA_ALLOWED_ERR = 6,
+ NO_MODIFICATION_ALLOWED_ERR = 7,
+ NOT_FOUND_ERR = 8,
+ NOT_SUPPORTED_ERR = 9,
+ INUSE_ATTRIBUTE_ERR = 10,
+
+ // Introduced in DOM Level 2:
+ INVALID_STATE_ERR = 11,
+ SYNTAX_ERR = 12,
+ INVALID_MODIFICATION_ERR = 13,
+ NAMESPACE_ERR = 14,
+ INVALID_ACCESS_ERR = 15,
+
+ // Introduced in DOM Level 3:
+ VALIDATION_ERR = 16,
+ TYPE_MISMATCH_ERR = 17
+ };
+
+ enum ExceptionType {
+ DOMExceptionType,
+ RangeExceptionType,
+ EventExceptionType,
+ XMLHttpRequestExceptionType
+#if ENABLE(XPATH)
+ , XPathExceptionType
+#endif
+#if ENABLE(SVG)
+ , SVGExceptionType
+#endif
+ };
+
+
+ struct ExceptionCodeDescription {
+ const char* typeName; // has spaces and is suitable for use in exception description strings; maximum length is 10 characters
+ const char* name; // exception name, also intended for use in exception description strings; 0 if name not known; maximum length is 27 characters
+ int code; // numeric value of the exception within a particular type
+ ExceptionType type;
+ };
+ void getExceptionCodeDescription(ExceptionCode, ExceptionCodeDescription&);
+
+} // namespace WebCore
+
+#endif // ExceptionCode_h
diff --git a/WebCore/dom/KeyboardEvent.cpp b/WebCore/dom/KeyboardEvent.cpp
new file mode 100644
index 0000000..0ee8cb5
--- /dev/null
+++ b/WebCore/dom/KeyboardEvent.cpp
@@ -0,0 +1,166 @@
+/**
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2003, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "KeyboardEvent.h"
+
+#include "Document.h"
+#include "DOMWindow.h"
+#include "EventNames.h"
+#include "EventHandler.h"
+#include "Frame.h"
+#include "PlatformKeyboardEvent.h"
+#include "Settings.h"
+
+namespace WebCore {
+
+using namespace EventNames;
+
+static inline const AtomicString& eventTypeForKeyboardEventType(PlatformKeyboardEvent::Type type)
+{
+ switch (type) {
+ case PlatformKeyboardEvent::KeyUp:
+ return keyupEvent;
+ case PlatformKeyboardEvent::RawKeyDown:
+ return keydownEvent;
+ case PlatformKeyboardEvent::Char:
+ return keypressEvent;
+ case PlatformKeyboardEvent::KeyDown:
+ // The caller should disambiguate the combined event into RawKeyDown or Char events.
+ break;
+ }
+ ASSERT_NOT_REACHED();
+ return keydownEvent;
+}
+
+KeyboardEvent::KeyboardEvent()
+ : m_keyEvent(0)
+ , m_keyLocation(DOM_KEY_LOCATION_STANDARD)
+ , m_altGraphKey(false)
+{
+}
+
+KeyboardEvent::KeyboardEvent(const PlatformKeyboardEvent& key, AbstractView* view)
+ : UIEventWithKeyState(eventTypeForKeyboardEventType(key.type()),
+ true, true, view, 0, key.ctrlKey(), key.altKey(), key.shiftKey(), key.metaKey())
+ , m_keyEvent(new PlatformKeyboardEvent(key))
+ , m_keyIdentifier(key.keyIdentifier())
+ , m_keyLocation(key.isKeypad() ? DOM_KEY_LOCATION_NUMPAD : DOM_KEY_LOCATION_STANDARD) // FIXME: differentiate right/left, too
+ , m_altGraphKey(false)
+{
+}
+
+KeyboardEvent::KeyboardEvent(const AtomicString& eventType, bool canBubble, bool cancelable, AbstractView *view,
+ const String &keyIdentifier, unsigned keyLocation,
+ bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, bool altGraphKey)
+ : UIEventWithKeyState(eventType, canBubble, cancelable, view, 0, ctrlKey, altKey, shiftKey, metaKey)
+ , m_keyEvent(0)
+ , m_keyIdentifier(keyIdentifier)
+ , m_keyLocation(keyLocation)
+ , m_altGraphKey(altGraphKey)
+{
+}
+
+KeyboardEvent::~KeyboardEvent()
+{
+ delete m_keyEvent;
+}
+
+void KeyboardEvent::initKeyboardEvent(const AtomicString& type, bool canBubble, bool cancelable, AbstractView* view,
+ const String &keyIdentifier, unsigned keyLocation,
+ bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, bool altGraphKey)
+{
+ if (dispatched())
+ return;
+
+ initUIEvent(type, canBubble, cancelable, view, 0);
+
+ m_keyIdentifier = keyIdentifier;
+ m_keyLocation = keyLocation;
+ m_ctrlKey = ctrlKey;
+ m_shiftKey = shiftKey;
+ m_altKey = altKey;
+ m_metaKey = metaKey;
+ m_altGraphKey = altGraphKey;
+}
+
+bool KeyboardEvent::getModifierState(const String& keyIdentifier) const
+{
+ if (keyIdentifier == "Control")
+ return ctrlKey();
+ if (keyIdentifier == "Shift")
+ return shiftKey();
+ if (keyIdentifier == "Alt")
+ return altKey();
+ if (keyIdentifier == "Meta")
+ return metaKey();
+ return false;
+}
+
+int KeyboardEvent::keyCode() const
+{
+ // IE: virtual key code for keyup/keydown, character code for keypress
+ // Firefox: virtual key code for keyup/keydown, zero for keypress
+ // We match IE.
+ if (!m_keyEvent)
+ return 0;
+ if (type() == keydownEvent || type() == keyupEvent)
+ return m_keyEvent->windowsVirtualKeyCode();
+ return charCode();
+}
+
+int KeyboardEvent::charCode() const
+{
+ // IE: not supported
+ // Firefox: 0 for keydown/keyup events, character code for keypress
+ // We match Firefox, unless in backward compatibility mode, where we always return the character code.
+ bool backwardCompatibilityMode = false;
+ if (view())
+ backwardCompatibilityMode = view()->frame()->eventHandler()->needsKeyboardEventDisambiguationQuirks();
+
+ if (!m_keyEvent || (type() != keypressEvent && !backwardCompatibilityMode))
+ return 0;
+ String text = m_keyEvent->text();
+ return static_cast<int>(text.characterStartingAt(0));
+}
+
+bool KeyboardEvent::isKeyboardEvent() const
+{
+ return true;
+}
+
+int KeyboardEvent::which() const
+{
+ // Netscape's "which" returns a virtual key code for keydown and keyup, and a character code for keypress.
+ // That's exactly what IE's "keyCode" returns. So they are the same for keyboard events.
+ return keyCode();
+}
+
+KeyboardEvent* findKeyboardEvent(Event* event)
+{
+ for (Event* e = event; e; e = e->underlyingEvent())
+ if (e->isKeyboardEvent())
+ return static_cast<KeyboardEvent*>(e);
+ return 0;
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/KeyboardEvent.h b/WebCore/dom/KeyboardEvent.h
new file mode 100644
index 0000000..c77d3d0
--- /dev/null
+++ b/WebCore/dom/KeyboardEvent.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef KeyboardEvent_h
+#define KeyboardEvent_h
+
+#include "UIEventWithKeyState.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+ class PlatformKeyboardEvent;
+
+#if PLATFORM(MAC)
+ struct KeypressCommand {
+ KeypressCommand(const String& commandName) : commandName(commandName) {}
+ KeypressCommand(const String& commandName, const String& text) : commandName(commandName), text(text) { ASSERT(commandName == "insertText:"); }
+
+ String commandName;
+ String text;
+ };
+#endif
+
+ // Introduced in DOM Level 3
+ class KeyboardEvent : public UIEventWithKeyState {
+ public:
+ enum KeyLocationCode {
+ DOM_KEY_LOCATION_STANDARD = 0x00,
+ DOM_KEY_LOCATION_LEFT = 0x01,
+ DOM_KEY_LOCATION_RIGHT = 0x02,
+ DOM_KEY_LOCATION_NUMPAD = 0x03
+ };
+
+ KeyboardEvent();
+ KeyboardEvent(const PlatformKeyboardEvent&, AbstractView*);
+ KeyboardEvent(const AtomicString& type, bool canBubble, bool cancelable, AbstractView*,
+ const String& keyIdentifier, unsigned keyLocation,
+ bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, bool altGraphKey);
+ virtual ~KeyboardEvent();
+
+ void initKeyboardEvent(const AtomicString& type, bool canBubble, bool cancelable, AbstractView*,
+ const String& keyIdentifier, unsigned keyLocation,
+ bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, bool altGraphKey = false);
+
+ String keyIdentifier() const { return m_keyIdentifier; }
+ unsigned keyLocation() const { return m_keyLocation; }
+
+ bool getModifierState(const String& keyIdentifier) const;
+
+ bool altGraphKey() const { return m_altGraphKey; }
+
+ const PlatformKeyboardEvent* keyEvent() const { return m_keyEvent; }
+
+ int keyCode() const; // key code for keydown and keyup, character for keypress
+ int charCode() const; // character code for keypress, 0 for keydown and keyup
+
+ virtual bool isKeyboardEvent() const;
+ virtual int which() const;
+
+#if PLATFORM(MAC)
+ // We only have this need to store keypress command info on the Mac.
+ Vector<KeypressCommand>& keypressCommands() { return m_keypressCommands; }
+#endif
+
+ private:
+ PlatformKeyboardEvent* m_keyEvent;
+ String m_keyIdentifier;
+ unsigned m_keyLocation;
+ bool m_altGraphKey : 1;
+
+#if PLATFORM(MAC)
+ Vector<KeypressCommand> m_keypressCommands;
+#endif
+ };
+
+ KeyboardEvent* findKeyboardEvent(Event*);
+
+} // namespace WebCore
+
+#endif // KeyboardEvent_h
diff --git a/WebCore/dom/KeyboardEvent.idl b/WebCore/dom/KeyboardEvent.idl
new file mode 100644
index 0000000..7e1f1ee
--- /dev/null
+++ b/WebCore/dom/KeyboardEvent.idl
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module events {
+
+ // Introduced in DOM Level 3:
+ interface [
+ GenerateConstructor
+ ] KeyboardEvent : UIEvent {
+
+#if !defined(LANGUAGE_JAVASCRIPT)
+ // KeyLocationCode
+ const unsigned long KEY_LOCATION_STANDARD = 0x00;
+ const unsigned long KEY_LOCATION_LEFT = 0x01;
+ const unsigned long KEY_LOCATION_RIGHT = 0x02;
+ const unsigned long KEY_LOCATION_NUMPAD = 0x03;
+#endif
+
+ readonly attribute DOMString keyIdentifier;
+ readonly attribute unsigned long keyLocation;
+ readonly attribute boolean ctrlKey;
+ readonly attribute boolean shiftKey;
+ readonly attribute boolean altKey;
+ readonly attribute boolean metaKey;
+ readonly attribute boolean altGraphKey;
+
+#if !defined(LANGUAGE_JAVASCRIPT)
+ boolean getModifierState(in DOMString keyIdentifierArg);
+#endif
+
+ // FIXME: this does not match the version in the DOM spec.
+ void initKeyboardEvent(in AtomicString type,
+ in boolean canBubble,
+ in boolean cancelable,
+ in DOMWindow view,
+ in DOMString keyIdentifier,
+ in unsigned long keyLocation,
+ in boolean ctrlKey,
+ in boolean altKey,
+ in boolean shiftKey,
+ in boolean metaKey,
+ in boolean altGraphKey);
+
+ // WebKit Extensions
+#if !defined(LANGUAGE_JAVASCRIPT)
+ readonly attribute long keyCode;
+ readonly attribute long charCode;
+
+ void initKeyboardEvent(in AtomicString type,
+ in boolean canBubble,
+ in boolean cancelable,
+ in DOMWindow view,
+ in DOMString keyIdentifier,
+ in unsigned long keyLocation,
+ in boolean ctrlKey,
+ in boolean altKey,
+ in boolean shiftKey,
+ in boolean metaKey);
+#endif
+
+ };
+
+}
diff --git a/WebCore/dom/MappedAttribute.cpp b/WebCore/dom/MappedAttribute.cpp
new file mode 100644
index 0000000..0bfeb5c
--- /dev/null
+++ b/WebCore/dom/MappedAttribute.cpp
@@ -0,0 +1,35 @@
+/**
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Peter Kelly (pmk@post.com)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include "config.h"
+#include "MappedAttribute.h"
+
+namespace WebCore {
+
+Attribute* MappedAttribute::clone(bool preserveDecl) const
+{
+ return new MappedAttribute(name(), value(), preserveDecl ? m_styleDecl.get() : 0);
+}
+
+}
diff --git a/WebCore/dom/MappedAttribute.h b/WebCore/dom/MappedAttribute.h
new file mode 100644
index 0000000..0ecc3cb
--- /dev/null
+++ b/WebCore/dom/MappedAttribute.h
@@ -0,0 +1,67 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Peter Kelly (pmk@post.com)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef MappedAttribute_h
+#define MappedAttribute_h
+
+#include "Attribute.h"
+#include "CSSMappedAttributeDeclaration.h"
+
+namespace WebCore {
+
+class Attr;
+class CSSStyleDeclaration;
+class CSSStyleSelector;
+class Element;
+class NamedAttrMap;
+
+class MappedAttribute : public Attribute
+{
+public:
+ MappedAttribute(const QualifiedName& name, const AtomicString& value, CSSMappedAttributeDeclaration* decl = 0)
+ : Attribute(name, value), m_styleDecl(decl)
+ {
+ }
+
+ MappedAttribute(const AtomicString& name, const AtomicString& value, CSSMappedAttributeDeclaration* decl = 0)
+ : Attribute(name, value), m_styleDecl(decl)
+ {
+ }
+
+ virtual Attribute* clone(bool preserveDecl=true) const;
+
+ virtual CSSStyleDeclaration* style() const { return m_styleDecl.get(); }
+
+ CSSMappedAttributeDeclaration* decl() const { return m_styleDecl.get(); }
+ void setDecl(CSSMappedAttributeDeclaration* decl) { m_styleDecl = decl; }
+
+private:
+ RefPtr<CSSMappedAttributeDeclaration> m_styleDecl;
+};
+
+} //namespace
+
+#endif
diff --git a/WebCore/dom/MappedAttributeEntry.h b/WebCore/dom/MappedAttributeEntry.h
new file mode 100644
index 0000000..745ad23
--- /dev/null
+++ b/WebCore/dom/MappedAttributeEntry.h
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Peter Kelly (pmk@post.com)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef MappedAttributeEntry_h
+#define MappedAttributeEntry_h
+
+namespace WebCore {
+
+enum MappedAttributeEntry {
+ eNone
+ , eUniversal
+ , ePersistent
+ , eReplaced
+ , eBlock
+ , eHR
+ , eUnorderedList
+ , eListItem
+ , eTable
+ , eCell
+ , eCaption
+ , eBDO
+ , ePre
+#if ENABLE(SVG)
+ , eSVG
+#endif
+// When adding new entries, make sure to keep eLastEntry at the end of the list.
+ , eLastEntry
+};
+
+}
+
+#endif
diff --git a/WebCore/dom/MessageEvent.cpp b/WebCore/dom/MessageEvent.cpp
new file mode 100644
index 0000000..06f253d
--- /dev/null
+++ b/WebCore/dom/MessageEvent.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2007 Henry Mason (hmason@mac.com)
+ * Copyright (C) 2003, 2005, 2006, 2007 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ *
+ */
+
+#include "config.h"
+
+#if ENABLE(CROSS_DOCUMENT_MESSAGING)
+
+#include "DOMWindow.h"
+#include "EventNames.h"
+#include "MessageEvent.h"
+
+namespace WebCore {
+
+using namespace EventNames;
+
+MessageEvent::MessageEvent()
+{
+}
+
+MessageEvent::MessageEvent(const String& data, const String& domain, const String& uri, DOMWindow* source)
+ : Event(messageEvent, true, true)
+ , m_data(data)
+ , m_domain(domain)
+ , m_uri(uri)
+ , m_source(source)
+{
+}
+
+MessageEvent::~MessageEvent()
+{
+}
+
+void MessageEvent::initMessageEvent(const AtomicString& type, bool canBubble, bool cancelable, const String& data, const String& domain, const String& uri, DOMWindow* source)
+{
+ if (dispatched())
+ return;
+
+ initEvent(type, canBubble, cancelable);
+
+ m_data = data;
+ m_domain = domain;
+ m_uri = uri;
+ m_source = source;
+}
+
+bool MessageEvent::isMessageEvent() const
+{
+ return true;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(CROSS_DOCUMENT_MESSAGING)
diff --git a/WebCore/dom/MessageEvent.h b/WebCore/dom/MessageEvent.h
new file mode 100644
index 0000000..f8b5f78
--- /dev/null
+++ b/WebCore/dom/MessageEvent.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2007 Henry Mason (hmason@mac.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 MessageEvent_h
+#define MessageEvent_h
+
+#if ENABLE(CROSS_DOCUMENT_MESSAGING)
+
+#include "Event.h"
+
+namespace WebCore {
+
+ class DOMWindow;
+
+ class MessageEvent : public Event {
+ public:
+ MessageEvent();
+ MessageEvent(const String& data, const String& domain, const String& uri, DOMWindow* source);
+ virtual ~MessageEvent();
+
+ void initMessageEvent(const AtomicString& type, bool canBubble, bool cancelable, const String& data, const String& domain, const String& uri, DOMWindow* source);
+
+ const String& data() const { return m_data; }
+ const String& domain() const { return m_domain; }
+ const String& uri() const { return m_uri; }
+ DOMWindow* source() const { return m_source.get(); }
+
+ virtual bool isMessageEvent() const;
+
+ private:
+ String m_data;
+ String m_domain;
+ String m_uri;
+ RefPtr<DOMWindow> m_source;
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(CROSS_DOCUMENT_MESSAGING)
+
+#endif // MessageEvent_h
diff --git a/WebCore/dom/MessageEvent.idl b/WebCore/dom/MessageEvent.idl
new file mode 100644
index 0000000..22f5262
--- /dev/null
+++ b/WebCore/dom/MessageEvent.idl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2007 Henry Mason <hmason@mac.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ *
+ */
+
+module events {
+
+ interface [Conditional=CROSS_DOCUMENT_MESSAGING,GenerateConstructor] MessageEvent : Event {
+
+ readonly attribute DOMString data;
+ readonly attribute DOMString domain;
+ readonly attribute DOMString uri;
+ readonly attribute DOMWindow source;
+
+ void initMessageEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString dataArg, in DOMString domainArg, in DOMString uriArg, in DOMWindow sourceArg);
+
+ };
+
+}
diff --git a/WebCore/dom/MouseEvent.cpp b/WebCore/dom/MouseEvent.cpp
new file mode 100644
index 0000000..245d620
--- /dev/null
+++ b/WebCore/dom/MouseEvent.cpp
@@ -0,0 +1,122 @@
+/**
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2003, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "MouseEvent.h"
+
+#include "EventNames.h"
+
+namespace WebCore {
+
+using namespace EventNames;
+
+MouseEvent::MouseEvent()
+ : m_button(0)
+ , m_buttonDown(false)
+{
+}
+
+MouseEvent::MouseEvent(const AtomicString& eventType, bool canBubble, bool cancelable, AbstractView* view,
+ int detail, int screenX, int screenY, int pageX, int pageY,
+ bool ctrlKey, bool altKey, bool shiftKey, bool metaKey,
+ unsigned short button, EventTargetNode* relatedTarget,
+ Clipboard* clipboard, bool isSimulated)
+ : MouseRelatedEvent(eventType, canBubble, cancelable, view, detail, screenX, screenY,
+ pageX, pageY, ctrlKey, altKey, shiftKey, metaKey, isSimulated)
+ , m_button(button == (unsigned short)-1 ? 0 : button)
+ , m_buttonDown(button != (unsigned short)-1)
+ , m_relatedTarget(relatedTarget)
+ , m_clipboard(clipboard)
+{
+}
+
+MouseEvent::~MouseEvent()
+{
+}
+
+void MouseEvent::initMouseEvent(const AtomicString& type, bool canBubble, bool cancelable, AbstractView* view,
+ int detail, int screenX, int screenY, int clientX, int clientY,
+ bool ctrlKey, bool altKey, bool shiftKey, bool metaKey,
+ unsigned short button, EventTargetNode* relatedTarget)
+{
+ if (dispatched())
+ return;
+
+ initUIEvent(type, canBubble, cancelable, view, detail);
+
+ m_screenX = screenX;
+ m_screenY = screenY;
+ m_ctrlKey = ctrlKey;
+ m_altKey = altKey;
+ m_shiftKey = shiftKey;
+ m_metaKey = metaKey;
+ m_button = button == (unsigned short)-1 ? 0 : button;
+ m_buttonDown = button != (unsigned short)-1;
+ m_relatedTarget = relatedTarget;
+
+ initCoordinates(clientX, clientY);
+
+ // FIXME: m_isSimulated is not set to false here.
+ // FIXME: m_clipboard is not set to 0 here.
+}
+
+bool MouseEvent::isMouseEvent() const
+{
+ return true;
+}
+
+bool MouseEvent::isDragEvent() const
+{
+ const AtomicString& t = type();
+ return t == dragenterEvent || t == dragoverEvent || t == dragleaveEvent || t == dropEvent
+ || t == dragstartEvent|| t == dragEvent || t == dragendEvent;
+}
+
+int MouseEvent::which() const
+{
+ // For the DOM, the return values for left, middle and right mouse buttons are 0, 1, 2, respectively.
+ // For the Netscape "which" property, the return values for left, middle and right mouse buttons are 1, 2, 3, respectively.
+ // So we must add 1.
+ return m_button + 1;
+}
+
+Node* MouseEvent::toElement() const
+{
+ // MSIE extension - "the object toward which the user is moving the mouse pointer"
+ if (type() == mouseoutEvent)
+ return relatedTarget();
+
+ return target() ? target()->toNode() : 0;
+}
+
+Node* MouseEvent::fromElement() const
+{
+ // MSIE extension - "object from which activation or the mouse pointer is exiting during the event" (huh?)
+ if (type() != mouseoutEvent)
+ return relatedTarget();
+
+ return target() ? target()->toNode() : 0;
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/MouseEvent.h b/WebCore/dom/MouseEvent.h
new file mode 100644
index 0000000..4a2d505
--- /dev/null
+++ b/WebCore/dom/MouseEvent.h
@@ -0,0 +1,76 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef MouseEvent_h
+#define MouseEvent_h
+
+#include "Clipboard.h"
+#include "EventTargetNode.h"
+#include "MouseRelatedEvent.h"
+
+namespace WebCore {
+
+ // Introduced in DOM Level 2
+ class MouseEvent : public MouseRelatedEvent {
+ public:
+ MouseEvent();
+ MouseEvent(const AtomicString& type, bool canBubble, bool cancelable, AbstractView* view,
+ int detail, int screenX, int screenY, int pageX, int pageY,
+ bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, unsigned short button,
+ EventTargetNode* relatedTarget, Clipboard* clipboard = 0, bool isSimulated = false);
+ virtual ~MouseEvent();
+
+ void initMouseEvent(const AtomicString& type, bool canBubble, bool cancelable, AbstractView* view,
+ int detail, int screenX, int screenY, int clientX, int clientY,
+ bool ctrlKey, bool altKey, bool shiftKey, bool metaKey,
+ unsigned short button, EventTargetNode* relatedTarget);
+
+ // WinIE uses 1,4,2 for left/middle/right but not for click (just for mousedown/up, maybe others),
+ // but we will match the standard DOM.
+ unsigned short button() const { return m_button; }
+ bool buttonDown() const { return m_buttonDown; }
+ EventTargetNode* relatedTarget() const { return m_relatedTarget.get(); }
+
+ Clipboard* clipboard() const { return m_clipboard.get(); }
+
+ Node* toElement() const;
+ Node* fromElement() const;
+
+ Clipboard* dataTransfer() const { return isDragEvent() ? m_clipboard.get() : 0; }
+
+ virtual bool isMouseEvent() const;
+ virtual bool isDragEvent() const;
+ virtual int which() const;
+
+ private:
+ unsigned short m_button;
+ bool m_buttonDown;
+ RefPtr<EventTargetNode> m_relatedTarget;
+ RefPtr<Clipboard> m_clipboard;
+ };
+
+} // namespace WebCore
+
+#endif // MouseEvent_h
diff --git a/WebCore/dom/MouseEvent.idl b/WebCore/dom/MouseEvent.idl
new file mode 100644
index 0000000..01f5215
--- /dev/null
+++ b/WebCore/dom/MouseEvent.idl
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module events {
+
+ // Introduced in DOM Level 2:
+ interface [
+ GenerateConstructor
+ ] MouseEvent : UIEvent {
+ readonly attribute long screenX;
+ readonly attribute long screenY;
+ readonly attribute long clientX;
+ readonly attribute long clientY;
+ readonly attribute boolean ctrlKey;
+ readonly attribute boolean shiftKey;
+ readonly attribute boolean altKey;
+ readonly attribute boolean metaKey;
+ readonly attribute unsigned short button;
+ readonly attribute EventTarget relatedTarget;
+
+ [OldStyleObjC] void initMouseEvent(in AtomicString type,
+ in boolean canBubble,
+ in boolean cancelable,
+ in DOMWindow view,
+ in long detail,
+ in long screenX,
+ in long screenY,
+ in long clientX,
+ in long clientY,
+ in boolean ctrlKey,
+ in boolean altKey,
+ in boolean shiftKey,
+ in boolean metaKey,
+ in unsigned short button,
+ in EventTarget relatedTarget);
+
+ // extensions
+ readonly attribute long offsetX;
+ readonly attribute long offsetY;
+ readonly attribute long x;
+ readonly attribute long y;
+ readonly attribute Node fromElement;
+ readonly attribute Node toElement;
+
+#if defined(LANGUAGE_JAVASCRIPT)
+ readonly attribute Clipboard dataTransfer;
+#endif
+ };
+
+}
diff --git a/WebCore/dom/MouseRelatedEvent.cpp b/WebCore/dom/MouseRelatedEvent.cpp
new file mode 100644
index 0000000..994cab5
--- /dev/null
+++ b/WebCore/dom/MouseRelatedEvent.cpp
@@ -0,0 +1,189 @@
+/**
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2003, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "MouseRelatedEvent.h"
+
+#include "DOMWindow.h"
+#include "Document.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "Node.h"
+#include "RenderLayer.h"
+#include "RenderObject.h"
+
+namespace WebCore {
+
+MouseRelatedEvent::MouseRelatedEvent()
+ : m_screenX(0)
+ , m_screenY(0)
+ , m_clientX(0)
+ , m_clientY(0)
+ , m_pageX(0)
+ , m_pageY(0)
+ , m_layerX(0)
+ , m_layerY(0)
+ , m_offsetX(0)
+ , m_offsetY(0)
+ , m_isSimulated(false)
+{
+}
+
+static int contentsX(AbstractView* abstractView)
+{
+ if (!abstractView)
+ return 0;
+ Frame* frame = abstractView->frame();
+ if (!frame)
+ return 0;
+ FrameView* frameView = frame->view();
+ if (!frameView)
+ return 0;
+ return frameView->contentsX();
+}
+
+static int contentsY(AbstractView* abstractView)
+{
+ if (!abstractView)
+ return 0;
+ Frame* frame = abstractView->frame();
+ if (!frame)
+ return 0;
+ FrameView* frameView = frame->view();
+ if (!frameView)
+ return 0;
+ return frameView->contentsY();
+}
+
+MouseRelatedEvent::MouseRelatedEvent(const AtomicString& eventType, bool canBubble, bool cancelable, AbstractView* view,
+ int detail, int screenX, int screenY, int pageX, int pageY,
+ bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, bool isSimulated)
+ : UIEventWithKeyState(eventType, canBubble, cancelable, view, detail, ctrlKey, altKey, shiftKey, metaKey)
+ , m_screenX(screenX)
+ , m_screenY(screenY)
+ , m_clientX(pageX - contentsX(view))
+ , m_clientY(pageY - contentsY(view))
+ , m_pageX(pageX)
+ , m_pageY(pageY)
+ , m_isSimulated(isSimulated)
+{
+ initCoordinates();
+}
+
+void MouseRelatedEvent::initCoordinates()
+{
+ // Set up initial values for coordinates.
+ // Correct values can't be computed until we have at target, so receivedTarget
+ // does the "real" computation.
+ m_layerX = m_pageX;
+ m_layerY = m_pageY;
+ m_offsetX = m_pageX;
+ m_offsetY = m_pageY;
+}
+
+void MouseRelatedEvent::initCoordinates(int clientX, int clientY)
+{
+ // Set up initial values for coordinates.
+ // Correct values can't be computed until we have at target, so receivedTarget
+ // does the "real" computation.
+ m_clientX = clientX;
+ m_clientY = clientY;
+ m_pageX = clientX + contentsX(view());
+ m_pageY = clientY + contentsY(view());
+ m_layerX = m_pageX;
+ m_layerY = m_pageY;
+ m_offsetX = m_pageX;
+ m_offsetY = m_pageY;
+}
+
+void MouseRelatedEvent::receivedTarget()
+{
+ ASSERT(target());
+ Node* targ = target()->toNode();
+ if (!targ)
+ return;
+
+ // Compute coordinates that are based on the target.
+ m_layerX = m_pageX;
+ m_layerY = m_pageY;
+ m_offsetX = m_pageX;
+ m_offsetY = m_pageY;
+
+ // Must have an updated render tree for this math to work correctly.
+ targ->document()->updateRendering();
+
+ // Adjust offsetX/Y to be relative to the target's position.
+ if (!isSimulated()) {
+ if (RenderObject* r = targ->renderer()) {
+ int rx, ry;
+ if (r->absolutePosition(rx, ry)) {
+ m_offsetX -= rx;
+ m_offsetY -= ry;
+ }
+ }
+ }
+
+ // Adjust layerX/Y to be relative to the layer.
+ // FIXME: We're pretty sure this is the wrong defintion of "layer."
+ // Our RenderLayer is a more modern concept, and layerX/Y is some
+ // other notion about groups of elements (left over from the Netscape 4 days?);
+ // we should test and fix this.
+ Node* n = targ;
+ while (n && !n->renderer())
+ n = n->parent();
+ if (n) {
+ RenderLayer* layer = n->renderer()->enclosingLayer();
+ layer->updateLayerPosition();
+ for (; layer; layer = layer->parent()) {
+ m_layerX -= layer->xPos();
+ m_layerY -= layer->yPos();
+ }
+ }
+}
+
+int MouseRelatedEvent::pageX() const
+{
+ return m_pageX;
+}
+
+int MouseRelatedEvent::pageY() const
+{
+ return m_pageY;
+}
+
+int MouseRelatedEvent::x() const
+{
+ // FIXME: This is not correct.
+ // See Microsoft documentation and <http://www.quirksmode.org/dom/w3c_events.html>.
+ return m_clientX;
+}
+
+int MouseRelatedEvent::y() const
+{
+ // FIXME: This is not correct.
+ // See Microsoft documentation and <http://www.quirksmode.org/dom/w3c_events.html>.
+ return m_clientY;
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/MouseRelatedEvent.h b/WebCore/dom/MouseRelatedEvent.h
new file mode 100644
index 0000000..9d88d58
--- /dev/null
+++ b/WebCore/dom/MouseRelatedEvent.h
@@ -0,0 +1,78 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef MouseRelatedEvent_h
+#define MouseRelatedEvent_h
+
+#include "UIEventWithKeyState.h"
+
+namespace WebCore {
+
+ // Internal only: Helper class for what's common between mouse and wheel events.
+ class MouseRelatedEvent : public UIEventWithKeyState {
+ public:
+ MouseRelatedEvent();
+ MouseRelatedEvent(const AtomicString& type, bool canBubble, bool cancelable, AbstractView* view,
+ int detail, int screenX, int screenY, int pageX, int pageY,
+ bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, bool isSimulated = false);
+
+ int screenX() const { return m_screenX; }
+ int screenY() const { return m_screenY; }
+ int clientX() const { return m_clientX; }
+ int clientY() const { return m_clientY; }
+ int layerX() const { return m_layerX; }
+ int layerY() const { return m_layerY; }
+ int offsetX() const { return m_offsetX; }
+ int offsetY() const { return m_offsetY; }
+ bool isSimulated() const { return m_isSimulated; }
+ virtual int pageX() const;
+ virtual int pageY() const;
+ int x() const;
+ int y() const;
+
+ protected:
+ void initCoordinates();
+ void initCoordinates(int clientX, int clientY);
+ virtual void receivedTarget();
+
+ // Expose these so MouseEvent::initMouseEvent can set them.
+ int m_screenX;
+ int m_screenY;
+ int m_clientX;
+ int m_clientY;
+
+ private:
+ int m_pageX;
+ int m_pageY;
+ int m_layerX;
+ int m_layerY;
+ int m_offsetX;
+ int m_offsetY;
+ bool m_isSimulated;
+ };
+
+} // namespace WebCore
+
+#endif // MouseRelatedEvent_h
diff --git a/WebCore/dom/MutationEvent.cpp b/WebCore/dom/MutationEvent.cpp
new file mode 100644
index 0000000..6ab577e
--- /dev/null
+++ b/WebCore/dom/MutationEvent.cpp
@@ -0,0 +1,68 @@
+/**
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2003, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "MutationEvent.h"
+
+namespace WebCore {
+
+MutationEvent::MutationEvent()
+ : m_attrChange(0)
+{
+}
+
+MutationEvent::MutationEvent(const AtomicString& type, bool canBubble, bool cancelable, Node* relatedNode,
+ const String& prevValue, const String& newValue,
+ const String& attrName, unsigned short attrChange)
+ : Event(type, canBubble, cancelable)
+ , m_relatedNode(relatedNode)
+ , m_prevValue(prevValue)
+ , m_newValue(newValue)
+ , m_attrName(attrName)
+ , m_attrChange(attrChange)
+{
+}
+
+void MutationEvent::initMutationEvent(const AtomicString& type, bool canBubble, bool cancelable, Node* relatedNode,
+ const String& prevValue, const String& newValue,
+ const String& attrName, unsigned short attrChange)
+{
+ if (dispatched())
+ return;
+
+ initEvent(type, canBubble, cancelable);
+
+ m_relatedNode = relatedNode;
+ m_prevValue = prevValue;
+ m_newValue = newValue;
+ m_attrName = attrName;
+ m_attrChange = attrChange;
+}
+
+bool MutationEvent::isMutationEvent() const
+{
+ return true;
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/MutationEvent.h b/WebCore/dom/MutationEvent.h
new file mode 100644
index 0000000..a820ed3
--- /dev/null
+++ b/WebCore/dom/MutationEvent.h
@@ -0,0 +1,69 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef MutationEvent_h
+#define MutationEvent_h
+
+#include "Event.h"
+#include "Node.h"
+
+namespace WebCore {
+
+ class MutationEvent : public Event {
+ public:
+ enum attrChangeType {
+ MODIFICATION = 1,
+ ADDITION = 2,
+ REMOVAL = 3
+ };
+
+ MutationEvent();
+ MutationEvent(const AtomicString& type, bool canBubble, bool cancelable, Node* relatedNode,
+ const String& prevValue, const String& newValue,
+ const String& attrName, unsigned short attrChange);
+
+ void initMutationEvent(const AtomicString& type, bool canBubble, bool cancelable, Node* relatedNode,
+ const String& prevValue, const String& newValue,
+ const String& attrName, unsigned short attrChange);
+
+ Node* relatedNode() const { return m_relatedNode.get(); }
+ String prevValue() const { return m_prevValue; }
+ String newValue() const { return m_newValue; }
+ String attrName() const { return m_attrName; }
+ unsigned short attrChange() const { return m_attrChange; }
+
+ virtual bool isMutationEvent() const;
+
+ private:
+ RefPtr<Node> m_relatedNode;
+ String m_prevValue;
+ String m_newValue;
+ String m_attrName;
+ unsigned short m_attrChange;
+ };
+
+} // namespace WebCore
+
+#endif // MutationEvent_h
diff --git a/WebCore/dom/MutationEvent.idl b/WebCore/dom/MutationEvent.idl
new file mode 100644
index 0000000..a383091
--- /dev/null
+++ b/WebCore/dom/MutationEvent.idl
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module events {
+
+ // Introduced in DOM Level 2:
+ interface [
+ GenerateConstructor
+ ] MutationEvent : Event {
+
+ // attrChangeType
+ const unsigned short MODIFICATION = 1;
+ const unsigned short ADDITION = 2;
+ const unsigned short REMOVAL = 3;
+
+ readonly attribute Node relatedNode;
+ readonly attribute DOMString prevValue;
+ readonly attribute DOMString newValue;
+ readonly attribute DOMString attrName;
+ readonly attribute unsigned short attrChange;
+
+ [OldStyleObjC] void initMutationEvent(in AtomicString type,
+ in boolean canBubble,
+ in boolean cancelable,
+ in Node relatedNode,
+ in DOMString prevValue,
+ in DOMString newValue,
+ in DOMString attrName,
+ in unsigned short attrChange);
+
+ };
+
+}
diff --git a/WebCore/dom/NameNodeList.cpp b/WebCore/dom/NameNodeList.cpp
new file mode 100644
index 0000000..be6e72b
--- /dev/null
+++ b/WebCore/dom/NameNodeList.cpp
@@ -0,0 +1,51 @@
+/**
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "NameNodeList.h"
+
+#include "Element.h"
+#include "HTMLNames.h"
+#include <wtf/Assertions.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+NameNodeList::NameNodeList(PassRefPtr<Node> rootNode, const String& name, DynamicNodeList::Caches* caches)
+ : DynamicNodeList(rootNode, caches, true)
+ , m_nodeName(name)
+{
+}
+
+void NameNodeList::rootNodeAttributeChanged()
+{
+ DynamicNodeList::rootNodeChildrenChanged();
+}
+
+bool NameNodeList::nodeMatches(Node* testNode) const
+{
+ ASSERT(testNode->isElementNode());
+ return static_cast<Element*>(testNode)->getAttribute(nameAttr) == m_nodeName;
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/NameNodeList.h b/WebCore/dom/NameNodeList.h
new file mode 100644
index 0000000..bb8c7f4
--- /dev/null
+++ b/WebCore/dom/NameNodeList.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef NameNodeList_h
+#define NameNodeList_h
+
+#include "DynamicNodeList.h"
+#include "AtomicString.h"
+
+namespace WebCore {
+
+ class String;
+
+ // NodeList which lists all Nodes in a Element with a given "name" attribute
+ class NameNodeList : public DynamicNodeList {
+ public:
+ NameNodeList(PassRefPtr<Node> rootNode, const String& name, DynamicNodeList::Caches*);
+
+ virtual void rootNodeAttributeChanged();
+
+ private:
+ virtual bool nodeMatches(Node*) const;
+
+ AtomicString m_nodeName;
+ };
+
+} // namespace WebCore
+
+#endif // NameNodeList_h
diff --git a/WebCore/dom/NamedAttrMap.cpp b/WebCore/dom/NamedAttrMap.cpp
new file mode 100644
index 0000000..ee89bcc
--- /dev/null
+++ b/WebCore/dom/NamedAttrMap.cpp
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Peter Kelly (pmk@post.com)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * (C) 2007 Eric Seidel (eric@webkit.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "NamedAttrMap.h"
+
+#include "Document.h"
+#include "Element.h"
+#include "ExceptionCode.h"
+#include "HTMLNames.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static inline bool shouldIgnoreAttributeCase(const Element* e)
+{
+ return e && e->document()->isHTMLDocument() && e->isHTMLElement();
+}
+
+NamedAttrMap::NamedAttrMap(Element *e)
+ : element(e)
+ , attrs(0)
+ , len(0)
+{
+}
+
+NamedAttrMap::~NamedAttrMap()
+{
+ NamedAttrMap::clearAttributes(); // virtual method, so qualify just to be explicit
+}
+
+bool NamedAttrMap::isMappedAttributeMap() const
+{
+ return false;
+}
+
+PassRefPtr<Node> NamedAttrMap::getNamedItem(const String& name) const
+{
+ String localName = shouldIgnoreAttributeCase(element) ? name.lower() : name;
+ Attribute* a = getAttributeItem(localName);
+ if (!a)
+ return 0;
+
+ return a->createAttrIfNeeded(element);
+}
+
+PassRefPtr<Node> NamedAttrMap::getNamedItemNS(const String& namespaceURI, const String& localName) const
+{
+ return getNamedItem(QualifiedName(nullAtom, localName, namespaceURI));
+}
+
+PassRefPtr<Node> NamedAttrMap::removeNamedItem(const String& name, ExceptionCode& ec)
+{
+ String localName = shouldIgnoreAttributeCase(element) ? name.lower() : name;
+ Attribute* a = getAttributeItem(localName);
+ if (!a) {
+ ec = NOT_FOUND_ERR;
+ return 0;
+ }
+
+ return removeNamedItem(a->name(), ec);
+}
+
+PassRefPtr<Node> NamedAttrMap::removeNamedItemNS(const String& namespaceURI, const String& localName, ExceptionCode& ec)
+{
+ return removeNamedItem(QualifiedName(nullAtom, localName, namespaceURI), ec);
+}
+
+PassRefPtr<Node> NamedAttrMap::getNamedItem(const QualifiedName& name) const
+{
+ Attribute* a = getAttributeItem(name);
+ if (!a)
+ return 0;
+
+ return a->createAttrIfNeeded(element);
+}
+
+PassRefPtr<Node> NamedAttrMap::setNamedItem(Node* arg, ExceptionCode& ec)
+{
+ if (!element) {
+ ec = NOT_FOUND_ERR;
+ return 0;
+ }
+
+ // NO_MODIFICATION_ALLOWED_ERR: Raised if this map is readonly.
+ if (isReadOnlyNode()) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return 0;
+ }
+
+ // WRONG_DOCUMENT_ERR: Raised if arg was created from a different document than the one that created this map.
+ if (arg->document() != element->document()) {
+ ec = WRONG_DOCUMENT_ERR;
+ return 0;
+ }
+
+ // Not mentioned in spec: throw a HIERARCHY_REQUEST_ERROR if the user passes in a non-attribute node
+ if (!arg->isAttributeNode()) {
+ ec = HIERARCHY_REQUEST_ERR;
+ return 0;
+ }
+ Attr *attr = static_cast<Attr*>(arg);
+
+ Attribute* a = attr->attr();
+ Attribute* old = getAttributeItem(a->name());
+ if (old == a)
+ return RefPtr<Node>(arg); // we know about it already
+
+ // INUSE_ATTRIBUTE_ERR: Raised if arg is an Attr that is already an attribute of another Element object.
+ // The DOM user must explicitly clone Attr nodes to re-use them in other elements.
+ if (attr->ownerElement()) {
+ ec = INUSE_ATTRIBUTE_ERR;
+ return 0;
+ }
+
+ if (a->name() == idAttr)
+ element->updateId(old ? old->value() : nullAtom, a->value());
+
+ // ### slightly inefficient - resizes attribute array twice.
+ RefPtr<Node> r;
+ if (old) {
+ r = old->createAttrIfNeeded(element);
+ removeAttribute(a->name());
+ }
+
+ addAttribute(a);
+ return r.release();
+}
+
+// The DOM2 spec doesn't say that removeAttribute[NS] throws NOT_FOUND_ERR
+// if the attribute is not found, but at this level we have to throw NOT_FOUND_ERR
+// because of removeNamedItem, removeNamedItemNS, and removeAttributeNode.
+PassRefPtr<Node> NamedAttrMap::removeNamedItem(const QualifiedName& name, ExceptionCode& ec)
+{
+ // ### should this really be raised when the attribute to remove isn't there at all?
+ // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly
+ if (isReadOnlyNode()) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return 0;
+ }
+
+ Attribute* a = getAttributeItem(name);
+ if (!a) {
+ ec = NOT_FOUND_ERR;
+ return 0;
+ }
+
+ RefPtr<Node> r = a->createAttrIfNeeded(element);
+
+ if (name == idAttr)
+ element->updateId(a->value(), nullAtom);
+
+ removeAttribute(name);
+ return r.release();
+}
+
+PassRefPtr<Node> NamedAttrMap::item ( unsigned index ) const
+{
+ if (index >= len)
+ return 0;
+
+ return attrs[index]->createAttrIfNeeded(element);
+}
+
+Attribute* NamedAttrMap::getAttributeItem(const String& name) const
+{
+ for (unsigned i = 0; i < len; ++i) {
+ if (!attrs[i]->name().hasPrefix() &&
+ attrs[i]->name().localName() == name)
+ return attrs[i];
+
+ if (attrs[i]->name().toString() == name)
+ return attrs[i];
+ }
+ return 0;
+}
+
+Attribute* NamedAttrMap::getAttributeItem(const QualifiedName& name) const
+{
+ for (unsigned i = 0; i < len; ++i) {
+ if (attrs[i]->name().matches(name))
+ return attrs[i];
+ }
+ return 0;
+}
+
+void NamedAttrMap::clearAttributes()
+{
+ if (attrs) {
+ for (unsigned i = 0; i < len; i++) {
+ if (attrs[i]->attr())
+ attrs[i]->attr()->m_element = 0;
+ attrs[i]->deref();
+ }
+ fastFree(attrs);
+ attrs = 0;
+ }
+ len = 0;
+}
+
+void NamedAttrMap::detachFromElement()
+{
+ // we allow a NamedAttrMap w/o an element in case someone still has a reference
+ // to if after the element gets deleted - but the map is now invalid
+ element = 0;
+ clearAttributes();
+}
+
+NamedAttrMap& NamedAttrMap::operator=(const NamedAttrMap& other)
+{
+ // clone all attributes in the other map, but attach to our element
+ if (!element)
+ return *this;
+
+ // If assigning the map changes the id attribute, we need to call
+ // updateId.
+
+ Attribute *oldId = getAttributeItem(idAttr);
+ Attribute *newId = other.getAttributeItem(idAttr);
+
+ if (oldId || newId)
+ element->updateId(oldId ? oldId->value() : nullAtom, newId ? newId->value() : nullAtom);
+
+ clearAttributes();
+ len = other.len;
+ attrs = static_cast<Attribute **>(fastMalloc(len * sizeof(Attribute *)));
+
+ // first initialize attrs vector, then call attributeChanged on it
+ // this allows attributeChanged to use getAttribute
+ for (unsigned i = 0; i < len; i++) {
+ attrs[i] = other.attrs[i]->clone();
+ attrs[i]->ref();
+ }
+
+ // FIXME: This is wasteful. The class list could be preserved on a copy, and we
+ // wouldn't have to waste time reparsing the attribute.
+ // The derived class, HTMLNamedAttrMap, which manages a parsed class list for the CLASS attribute,
+ // will update its member variable when parse attribute is called.
+ for(unsigned i = 0; i < len; i++)
+ element->attributeChanged(attrs[i], true);
+
+ return *this;
+}
+
+void NamedAttrMap::addAttribute(PassRefPtr<Attribute> prpAttribute)
+{
+ Attribute* attribute = prpAttribute.releaseRef(); // The attrs array will own this pointer.
+
+ // Add the attribute to the list
+ attrs = static_cast<Attribute**>(fastRealloc(attrs, (len + 1) * sizeof(Attribute*)));
+ attrs[len++] = attribute;
+
+ if (Attr* attr = attribute->attr())
+ attr->m_element = element;
+
+ // Notify the element that the attribute has been added, and dispatch appropriate mutation events
+ // Note that element may be null here if we are called from insertAttr() during parsing
+ if (element) {
+ element->attributeChanged(attribute);
+ // Because of our updateStyleAttributeIfNeeded() style modification events are never sent at the right time, so don't bother sending them.
+ if (attribute->name() != styleAttr) {
+ element->dispatchAttrAdditionEvent(attribute);
+ element->dispatchSubtreeModifiedEvent();
+ }
+ }
+}
+
+void NamedAttrMap::removeAttribute(const QualifiedName& name)
+{
+ unsigned index = len+1;
+ for (unsigned i = 0; i < len; ++i)
+ if (attrs[i]->name().matches(name)) {
+ index = i;
+ break;
+ }
+
+ if (index >= len) return;
+
+ // Remove the attribute from the list
+ Attribute* attr = attrs[index];
+ if (attrs[index]->attr())
+ attrs[index]->attr()->m_element = 0;
+ if (len == 1) {
+ fastFree(attrs);
+ attrs = 0;
+ len = 0;
+ } else {
+ Attribute **newAttrs = static_cast<Attribute **>(fastMalloc((len - 1) * sizeof(Attribute *)));
+ unsigned i;
+ for (i = 0; i < unsigned(index); i++)
+ newAttrs[i] = attrs[i];
+ len--;
+ for (; i < len; i++)
+ newAttrs[i] = attrs[i+1];
+ fastFree(attrs);
+ attrs = newAttrs;
+ }
+
+ // Notify the element that the attribute has been removed
+ // dispatch appropriate mutation events
+ if (element && !attr->m_value.isNull()) {
+ AtomicString value = attr->m_value;
+ attr->m_value = nullAtom;
+ element->attributeChanged(attr);
+ attr->m_value = value;
+ }
+ if (element) {
+ element->dispatchAttrRemovalEvent(attr);
+ element->dispatchSubtreeModifiedEvent();
+ }
+ attr->deref();
+}
+
+bool NamedAttrMap::mapsEquivalent(const NamedAttrMap* otherMap) const
+{
+ if (!otherMap)
+ return false;
+
+ if (length() != otherMap->length())
+ return false;
+
+ for (unsigned i = 0; i < length(); i++) {
+ Attribute *attr = attributeItem(i);
+ Attribute *otherAttr = otherMap->getAttributeItem(attr->name());
+
+ if (!otherAttr || attr->value() != otherAttr->value())
+ return false;
+ }
+
+ return true;
+}
+
+bool NamedAttrMap::isReadOnlyNode()
+{
+ return element && element->isReadOnlyNode();
+}
+
+}
diff --git a/WebCore/dom/NamedAttrMap.h b/WebCore/dom/NamedAttrMap.h
new file mode 100644
index 0000000..dd57284
--- /dev/null
+++ b/WebCore/dom/NamedAttrMap.h
@@ -0,0 +1,103 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Peter Kelly (pmk@post.com)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef NamedAttrMap_h
+#define NamedAttrMap_h
+
+#include "Attribute.h"
+#include "NamedNodeMap.h"
+
+#ifdef __OBJC__
+#define id id_AVOID_KEYWORD
+#endif
+
+namespace WebCore {
+
+// the map of attributes of an element
+class NamedAttrMap : public NamedNodeMap {
+ friend class Element;
+public:
+ NamedAttrMap(Element*);
+ virtual ~NamedAttrMap();
+ NamedAttrMap(const NamedAttrMap&);
+ NamedAttrMap &operator =(const NamedAttrMap &other);
+
+ // DOM methods & attributes for NamedNodeMap
+
+ virtual PassRefPtr<Node> getNamedItem(const String& name) const;
+ virtual PassRefPtr<Node> removeNamedItem(const String& name, ExceptionCode&);
+
+ virtual PassRefPtr<Node> getNamedItemNS(const String& namespaceURI, const String& localName) const;
+ virtual PassRefPtr<Node> removeNamedItemNS(const String& namespaceURI, const String& localName, ExceptionCode&);
+
+ virtual PassRefPtr<Node> getNamedItem(const QualifiedName& name) const;
+ virtual PassRefPtr<Node> removeNamedItem(const QualifiedName& name, ExceptionCode&);
+ virtual PassRefPtr<Node> setNamedItem(Node* arg, ExceptionCode&);
+
+ virtual PassRefPtr<Node> item(unsigned index) const;
+ unsigned length() const { return len; }
+
+ // Other methods (not part of DOM)
+ Attribute* attributeItem(unsigned index) const { return attrs[index]; }
+ Attribute* getAttributeItem(const QualifiedName& name) const;
+ Attribute* getAttributeItem(const String& name) const;
+ virtual bool isReadOnlyNode();
+
+ // used during parsing: only inserts if not already there
+ // no error checking!
+ void insertAttribute(PassRefPtr<Attribute> newAttribute, bool allowDuplicates)
+ {
+ ASSERT(!element);
+ if (allowDuplicates || !getAttributeItem(newAttribute->name()))
+ addAttribute(newAttribute);
+ }
+
+ virtual bool isMappedAttributeMap() const;
+
+ const AtomicString& id() const { return m_id; }
+ void setID(const AtomicString& _id) { m_id = _id; }
+
+ bool mapsEquivalent(const NamedAttrMap* otherMap) const;
+
+protected:
+ // this method is internal, does no error checking at all
+ void addAttribute(PassRefPtr<Attribute>);
+ // this method is internal, does no error checking at all
+ void removeAttribute(const QualifiedName& name);
+ virtual void clearAttributes();
+ void detachFromElement();
+
+ Element *element;
+ Attribute **attrs;
+ unsigned len;
+ AtomicString m_id;
+};
+
+} //namespace
+
+#undef id
+
+#endif
diff --git a/WebCore/dom/NamedMappedAttrMap.cpp b/WebCore/dom/NamedMappedAttrMap.cpp
new file mode 100644
index 0000000..afa4d76
--- /dev/null
+++ b/WebCore/dom/NamedMappedAttrMap.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Peter Kelly (pmk@post.com)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * (C) 2007 David Smith (catfish.man@gmail.com)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "NamedMappedAttrMap.h"
+
+#include "Document.h"
+#include "Element.h"
+
+namespace WebCore {
+
+NamedMappedAttrMap::NamedMappedAttrMap(Element *e)
+ : NamedAttrMap(e)
+ , m_mappedAttributeCount(0)
+{
+}
+
+void NamedMappedAttrMap::clearAttributes()
+{
+ m_classNames.clear();
+ m_mappedAttributeCount = 0;
+ NamedAttrMap::clearAttributes();
+}
+
+bool NamedMappedAttrMap::isMappedAttributeMap() const
+{
+ return true;
+}
+
+int NamedMappedAttrMap::declCount() const
+{
+ int result = 0;
+ for (unsigned i = 0; i < length(); i++) {
+ MappedAttribute* attr = attributeItem(i);
+ if (attr->decl())
+ result++;
+ }
+ return result;
+}
+
+bool NamedMappedAttrMap::mapsEquivalent(const NamedMappedAttrMap* otherMap) const
+{
+ // The # of decls must match.
+ if (declCount() != otherMap->declCount())
+ return false;
+
+ // The values for each decl must match.
+ for (unsigned i = 0; i < length(); i++) {
+ MappedAttribute* attr = attributeItem(i);
+ if (attr->decl()) {
+ Attribute* otherAttr = otherMap->getAttributeItem(attr->name());
+ if (!otherAttr || (attr->value() != otherAttr->value()))
+ return false;
+ }
+ }
+ return true;
+}
+
+void NamedMappedAttrMap::parseClassAttribute(const String& classStr)
+{
+ if (!element->hasClass()) {
+ m_classNames.clear();
+ return;
+ }
+
+ m_classNames.parseClassAttribute(classStr, element->document()->inCompatMode());
+}
+
+
+}
diff --git a/WebCore/dom/NamedMappedAttrMap.h b/WebCore/dom/NamedMappedAttrMap.h
new file mode 100644
index 0000000..2889a34
--- /dev/null
+++ b/WebCore/dom/NamedMappedAttrMap.h
@@ -0,0 +1,71 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Peter Kelly (pmk@post.com)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * (C) 2007 David Smith (catfish.man@gmail.com)
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef NamedMappedAttrMap_h
+#define NamedMappedAttrMap_h
+
+#include "ClassNames.h"
+#include "MappedAttribute.h"
+#include "NamedAttrMap.h"
+
+namespace WebCore {
+
+class NamedMappedAttrMap : public NamedAttrMap
+{
+public:
+ NamedMappedAttrMap(Element *e);
+
+ virtual void clearAttributes();
+
+ virtual bool isMappedAttributeMap() const;
+
+ void parseClassAttribute(const String&);
+
+ const ClassNames* getClassNames() const { return &m_classNames; }
+
+ virtual bool hasMappedAttributes() const { return m_mappedAttributeCount > 0; }
+ void declRemoved() { m_mappedAttributeCount--; }
+ void declAdded() { m_mappedAttributeCount++; }
+
+ bool mapsEquivalent(const NamedMappedAttrMap* otherMap) const;
+ int declCount() const;
+
+ MappedAttribute* attributeItem(unsigned index) const
+ { return static_cast<MappedAttribute*>(NamedAttrMap::attributeItem(index)); }
+ MappedAttribute* getAttributeItem(const QualifiedName& name) const
+ { return static_cast<MappedAttribute*>(NamedAttrMap::getAttributeItem(name)); }
+ MappedAttribute* getAttributeItem(const String& name) const
+ { return static_cast<MappedAttribute*>(NamedAttrMap::getAttributeItem(name)); }
+
+private:
+ ClassNames m_classNames;
+ int m_mappedAttributeCount;
+};
+
+} //namespace
+
+#endif
diff --git a/WebCore/dom/NamedNodeMap.h b/WebCore/dom/NamedNodeMap.h
new file mode 100644
index 0000000..cc70bea
--- /dev/null
+++ b/WebCore/dom/NamedNodeMap.h
@@ -0,0 +1,68 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef NamedNodeMap_h
+#define NamedNodeMap_h
+
+#include <wtf/RefCounted.h>
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+class Node;
+class QualifiedName;
+class String;
+
+typedef int ExceptionCode;
+
+// Generic NamedNodeMap interface
+// Other classes implement this for more specific situations e.g. attributes of an element.
+class NamedNodeMap : public RefCounted<NamedNodeMap> {
+public:
+ NamedNodeMap() : RefCounted<NamedNodeMap>(0) { }
+ virtual ~NamedNodeMap() { }
+
+ virtual PassRefPtr<Node> getNamedItem(const String& name) const = 0;
+ virtual PassRefPtr<Node> removeNamedItem(const String& name, ExceptionCode&) = 0;
+
+ virtual PassRefPtr<Node> getNamedItemNS(const String& namespaceURI, const String& localName) const = 0;
+ PassRefPtr<Node> setNamedItemNS(Node* arg, ExceptionCode& ec) { return setNamedItem(arg, ec); }
+ virtual PassRefPtr<Node> removeNamedItemNS(const String& namespaceURI, const String& localName, ExceptionCode&) = 0;
+
+ // DOM methods & attributes for NamedNodeMap
+ virtual PassRefPtr<Node> getNamedItem(const QualifiedName& attrName) const = 0;
+ virtual PassRefPtr<Node> removeNamedItem(const QualifiedName& attrName, ExceptionCode&) = 0;
+ virtual PassRefPtr<Node> setNamedItem(Node*, ExceptionCode&) = 0;
+
+ virtual PassRefPtr<Node> item(unsigned index) const = 0;
+ virtual unsigned length() const = 0;
+
+ // Other methods (not part of DOM)
+ virtual bool isReadOnlyNode() { return false; }
+};
+
+} //namespace
+
+#endif
diff --git a/WebCore/dom/NamedNodeMap.idl b/WebCore/dom/NamedNodeMap.idl
new file mode 100644
index 0000000..3310ded
--- /dev/null
+++ b/WebCore/dom/NamedNodeMap.idl
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module core {
+
+ interface [
+ GenerateConstructor,
+ HasIndexGetter,
+ HasNameGetter,
+ InterfaceUUID=08DAF7A4-4C32-4709-B72F-622721FF0FB8,
+ ImplementationUUID=A1CC9F5B-092D-4a04-96D9-D7718A8D6242
+ ] NamedNodeMap {
+
+ Node getNamedItem(in DOMString name);
+
+ Node setNamedItem(in Node node)
+ raises(DOMException);
+
+ Node removeNamedItem(in DOMString name)
+ raises(DOMException);
+
+ Node item(in unsigned long index);
+
+ readonly attribute unsigned long length;
+
+
+ // Introduced in DOM Level 2:
+
+ [OldStyleObjC] Node getNamedItemNS(in [ConvertNullToNullString] DOMString namespaceURI,
+ in DOMString localName)
+ // FIXME: the implementation does take an exceptioncode parameter.
+ /*raises(DOMException)*/;
+
+ Node setNamedItemNS(in Node node)
+ raises(DOMException);
+
+ [OldStyleObjC] Node removeNamedItemNS(in [ConvertNullToNullString] DOMString namespaceURI,
+ in DOMString localName)
+ raises(DOMException);
+
+ };
+
+}
diff --git a/WebCore/dom/Node.cpp b/WebCore/dom/Node.cpp
new file mode 100644
index 0000000..8a52e0e
--- /dev/null
+++ b/WebCore/dom/Node.cpp
@@ -0,0 +1,1656 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Trolltech ASA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "Node.h"
+
+#include "CSSParser.h"
+#include "CSSRule.h"
+#include "CSSRuleList.h"
+#include "CSSSelector.h"
+#include "CSSStyleRule.h"
+#include "CSSStyleSelector.h"
+#include "CSSStyleSheet.h"
+#include "CString.h"
+#include "ChildNodeList.h"
+#include "ClassNodeList.h"
+#include "DOMImplementation.h"
+#include "Document.h"
+#include "DynamicNodeList.h"
+#include "Element.h"
+#include "ExceptionCode.h"
+#include "Frame.h"
+#include "HTMLNames.h"
+#include "HTMLNames.h"
+#include "Logging.h"
+#include "NameNodeList.h"
+#include "NamedAttrMap.h"
+#include "RenderObject.h"
+#include "SelectorNodeList.h"
+#include "TagNodeList.h"
+#include "Text.h"
+#include "XMLNames.h"
+#include "htmlediting.h"
+#include "kjs_binding.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+typedef HashSet<DynamicNodeList*> NodeListSet;
+struct NodeListsNodeData {
+ NodeListSet m_listsToNotify;
+ DynamicNodeList::Caches m_childNodeListCaches;
+
+ typedef HashMap<String, DynamicNodeList::Caches*> CacheMap;
+ CacheMap m_classNodeListCaches;
+ CacheMap m_nameNodeListCaches;
+
+ ~NodeListsNodeData()
+ {
+ deleteAllValues(m_classNodeListCaches);
+ deleteAllValues(m_nameNodeListCaches);
+ }
+};
+
+bool Node::isSupported(const String& feature, const String& version)
+{
+ return DOMImplementation::instance()->hasFeature(feature, version);
+}
+
+#ifndef NDEBUG
+WTFLogChannel LogWebCoreNodeLeaks = { 0x00000000, "", WTFLogChannelOn };
+
+struct NodeCounter {
+ static unsigned count;
+
+ ~NodeCounter()
+ {
+ if (count)
+ LOG(WebCoreNodeLeaks, "LEAK: %u Node\n", count);
+ }
+};
+unsigned NodeCounter::count = 0;
+static NodeCounter nodeCounter;
+
+static bool shouldIgnoreLeaks = false;
+static HashSet<Node*> ignoreSet;
+#endif
+
+void Node::startIgnoringLeaks()
+{
+#ifndef NDEBUG
+ shouldIgnoreLeaks = true;
+#endif
+}
+
+void Node::stopIgnoringLeaks()
+{
+#ifndef NDEBUG
+ shouldIgnoreLeaks = false;
+#endif
+}
+
+Node::Node(Document *doc)
+ : m_document(doc),
+ m_previous(0),
+ m_next(0),
+ m_renderer(0),
+ m_tabIndex(0),
+ m_hasId(false),
+ m_hasClass(false),
+ m_attached(false),
+ m_styleChange(NoStyleChange),
+ m_hasChangedChild(false),
+ m_inDocument(false),
+ m_isLink(false),
+ m_attrWasSpecifiedOrElementHasRareData(false),
+ m_focused(false),
+ m_active(false),
+ m_hovered(false),
+ m_inActiveChain(false),
+ m_inDetach(false),
+ m_dispatchingSimulatedEvent(false),
+ m_inSubtreeMark(false)
+{
+#ifndef NDEBUG
+ if (shouldIgnoreLeaks)
+ ignoreSet.add(this);
+ else
+ ++NodeCounter::count;
+#endif
+}
+
+void Node::setDocument(Document* doc)
+{
+ if (inDocument() || m_document == doc)
+ return;
+
+ willMoveToNewOwnerDocument();
+
+ {
+ KJS::JSLock lock;
+ ScriptInterpreter::updateDOMNodeDocument(this, m_document.get(), doc);
+ }
+ m_document = doc;
+
+ didMoveToNewOwnerDocument();
+}
+
+Node::~Node()
+{
+#ifndef NDEBUG
+ HashSet<Node*>::iterator it = ignoreSet.find(this);
+ if (it != ignoreSet.end())
+ ignoreSet.remove(it);
+ else
+ --NodeCounter::count;
+#endif
+ if (renderer())
+ detach();
+
+ if (m_previous)
+ m_previous->setNextSibling(0);
+ if (m_next)
+ m_next->setPreviousSibling(0);
+}
+
+String Node::nodeValue() const
+{
+ return String();
+}
+
+void Node::setNodeValue(const String& /*nodeValue*/, ExceptionCode& ec)
+{
+ // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly
+ if (isReadOnlyNode()) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return;
+ }
+
+ // by default nodeValue is null, so setting it has no effect
+}
+
+PassRefPtr<NodeList> Node::childNodes()
+{
+ if (!m_nodeLists)
+ m_nodeLists.set(new NodeListsNodeData);
+
+ return new ChildNodeList(this, &m_nodeLists->m_childNodeListCaches);
+}
+
+Node* Node::virtualFirstChild() const
+{
+ return 0;
+}
+
+Node* Node::virtualLastChild() const
+{
+ return 0;
+}
+
+bool Node::virtualHasTagName(const QualifiedName&) const
+{
+ return false;
+}
+
+Node *Node::lastDescendant() const
+{
+ Node *n = const_cast<Node *>(this);
+ while (n && n->lastChild())
+ n = n->lastChild();
+ return n;
+}
+
+Node* Node::firstDescendant() const
+{
+ Node *n = const_cast<Node *>(this);
+ while (n && n->firstChild())
+ n = n->firstChild();
+ return n;
+}
+
+bool Node::insertBefore(PassRefPtr<Node>, Node*, ExceptionCode& ec)
+{
+ ec = HIERARCHY_REQUEST_ERR;
+ return false;
+}
+
+bool Node::replaceChild(PassRefPtr<Node>, Node*, ExceptionCode& ec)
+{
+ ec = HIERARCHY_REQUEST_ERR;
+ return false;
+}
+
+bool Node::removeChild(Node*, ExceptionCode& ec)
+{
+ ec = NOT_FOUND_ERR;
+ return false;
+}
+
+bool Node::appendChild(PassRefPtr<Node>, ExceptionCode& ec)
+{
+ ec = HIERARCHY_REQUEST_ERR;
+ return false;
+}
+
+void Node::remove(ExceptionCode& ec)
+{
+ ref();
+ if (Node *p = parentNode())
+ p->removeChild(this, ec);
+ else
+ ec = HIERARCHY_REQUEST_ERR;
+ deref();
+}
+
+bool Node::hasChildNodes( ) const
+{
+ return false;
+}
+
+void Node::normalize ()
+{
+ ExceptionCode ec = 0;
+ Node *child = firstChild();
+
+ if (isElementNode()) {
+ // Normalize any attribute children we might have
+ Element *element = static_cast<Element *>(this);
+ NamedAttrMap *attrMap = element->attributes();
+
+ if (attrMap) {
+ unsigned numAttrs = attrMap->length();
+
+ for (unsigned i = 0; i < numAttrs; i++) {
+ Attribute *attribute = attrMap->attributeItem(i);
+ Attr *attr = attribute->attr();
+
+ if (attr)
+ attr->normalize();
+ }
+ }
+ }
+
+ // Recursively go through the subtree beneath us, normalizing all nodes. In the case
+ // where there are two adjacent text nodes, they are merged together
+ while (child) {
+ Node *nextChild = child->nextSibling();
+
+ if (nextChild && child->nodeType() == TEXT_NODE && nextChild->nodeType() == TEXT_NODE) {
+ // Current child and the next one are both text nodes... merge them
+ Text *currentText = static_cast<Text*>(child);
+ Text *nextText = static_cast<Text*>(nextChild);
+
+ currentText->appendData(nextText->data(),ec);
+ if (ec)
+ return;
+
+ nextChild->remove(ec);
+ if (ec)
+ return;
+ }
+ else {
+ child->normalize();
+ child = nextChild;
+ }
+ }
+
+ // Check if we have a single empty text node left and remove it if so
+ child = firstChild();
+ if (child && !child->nextSibling() && child->isTextNode()) {
+ Text *text = static_cast<Text*>(child);
+ if (text->data().isEmpty())
+ child->remove(ec);
+ }
+}
+
+const AtomicString& Node::prefix() const
+{
+ // For nodes other than elements and attributes, the prefix is always null
+ return nullAtom;
+}
+
+void Node::setPrefix(const AtomicString& /*prefix*/, ExceptionCode& ec)
+{
+ // The spec says that for nodes other than elements and attributes, prefix is always null.
+ // It does not say what to do when the user tries to set the prefix on another type of
+ // node, however Mozilla throws a NAMESPACE_ERR exception.
+ ec = NAMESPACE_ERR;
+}
+
+const AtomicString& Node::localName() const
+{
+ return nullAtom;
+}
+
+const AtomicString& Node::namespaceURI() const
+{
+ return nullAtom;
+}
+
+ContainerNode* Node::addChild(PassRefPtr<Node>)
+{
+ return 0;
+}
+
+bool Node::isContentEditable() const
+{
+ return parent() && parent()->isContentEditable();
+}
+
+bool Node::isContentRichlyEditable() const
+{
+ return parent() && parent()->isContentRichlyEditable();
+}
+
+bool Node::shouldUseInputMethod() const
+{
+ return isContentEditable();
+}
+
+IntRect Node::getRect() const
+{
+ int _x, _y;
+ if (renderer() && renderer()->absolutePosition(_x, _y))
+ return IntRect( _x, _y, renderer()->width(), renderer()->height() + renderer()->borderTopExtra() + renderer()->borderBottomExtra());
+
+ return IntRect();
+}
+
+void Node::setChanged(StyleChangeType changeType)
+{
+ if ((changeType != NoStyleChange) && !attached()) // changed compared to what?
+ return;
+
+ if (!(changeType == InlineStyleChange && m_styleChange == FullStyleChange))
+ m_styleChange = changeType;
+
+ if (m_styleChange != NoStyleChange) {
+ for (Node* p = parentNode(); p; p = p->parentNode())
+ p->setHasChangedChild(true);
+ document()->setDocumentChanged(true);
+ }
+}
+
+bool Node::isFocusable() const
+{
+ return false;
+}
+
+bool Node::isKeyboardFocusable(KeyboardEvent*) const
+{
+ return isFocusable();
+}
+
+bool Node::isMouseFocusable() const
+{
+ return isFocusable();
+}
+
+unsigned Node::nodeIndex() const
+{
+ Node *_tempNode = previousSibling();
+ unsigned count=0;
+ for( count=0; _tempNode; count++ )
+ _tempNode = _tempNode->previousSibling();
+ return count;
+}
+
+void Node::registerDynamicNodeList(DynamicNodeList* list)
+{
+ if (!m_nodeLists)
+ m_nodeLists.set(new NodeListsNodeData);
+ else if (!m_document->hasNodeLists())
+ // We haven't been receiving notifications while there were no registered lists, so the cache is invalid now.
+ m_nodeLists->m_childNodeListCaches.reset();
+
+ if (list->needsNotifications())
+ m_nodeLists->m_listsToNotify.add(list);
+ m_document->addNodeList();
+}
+
+void Node::unregisterDynamicNodeList(DynamicNodeList* list)
+{
+ ASSERT(m_nodeLists);
+ m_document->removeNodeList();
+ if (list->needsNotifications())
+ m_nodeLists->m_listsToNotify.remove(list);
+}
+
+void Node::notifyLocalNodeListsAttributeChanged()
+{
+ if (!m_nodeLists)
+ return;
+
+ NodeListSet::iterator end = m_nodeLists->m_listsToNotify.end();
+ for (NodeListSet::iterator i = m_nodeLists->m_listsToNotify.begin(); i != end; ++i)
+ (*i)->rootNodeAttributeChanged();
+}
+
+void Node::notifyNodeListsAttributeChanged()
+{
+ for (Node *n = this; n; n = n->parentNode())
+ n->notifyLocalNodeListsAttributeChanged();
+}
+
+void Node::notifyLocalNodeListsChildrenChanged()
+{
+ if (!m_nodeLists)
+ return;
+
+ m_nodeLists->m_childNodeListCaches.reset();
+
+ NodeListSet::iterator end = m_nodeLists->m_listsToNotify.end();
+ for (NodeListSet::iterator i = m_nodeLists->m_listsToNotify.begin(); i != end; ++i)
+ (*i)->rootNodeChildrenChanged();
+}
+
+void Node::notifyNodeListsChildrenChanged()
+{
+ for (Node *n = this; n; n = n->parentNode())
+ n->notifyLocalNodeListsChildrenChanged();
+}
+
+unsigned Node::childNodeCount() const
+{
+ return 0;
+}
+
+Node *Node::childNode(unsigned /*index*/) const
+{
+ return 0;
+}
+
+Node *Node::traverseNextNode(const Node *stayWithin) const
+{
+ if (firstChild())
+ return firstChild();
+ if (this == stayWithin)
+ return 0;
+ if (nextSibling())
+ return nextSibling();
+ const Node *n = this;
+ while (n && !n->nextSibling() && (!stayWithin || n->parentNode() != stayWithin))
+ n = n->parentNode();
+ if (n)
+ return n->nextSibling();
+ return 0;
+}
+
+Node *Node::traverseNextSibling(const Node *stayWithin) const
+{
+ if (this == stayWithin)
+ return 0;
+ if (nextSibling())
+ return nextSibling();
+ const Node *n = this;
+ while (n && !n->nextSibling() && (!stayWithin || n->parentNode() != stayWithin))
+ n = n->parentNode();
+ if (n)
+ return n->nextSibling();
+ return 0;
+}
+
+Node *Node::traversePreviousNode(const Node *stayWithin) const
+{
+ if (this == stayWithin)
+ return 0;
+ if (previousSibling()) {
+ Node *n = previousSibling();
+ while (n->lastChild())
+ n = n->lastChild();
+ return n;
+ }
+ return parentNode();
+}
+
+Node *Node::traversePreviousNodePostOrder(const Node *stayWithin) const
+{
+ if (lastChild())
+ return lastChild();
+ if (this == stayWithin)
+ return 0;
+ if (previousSibling())
+ return previousSibling();
+ const Node *n = this;
+ while (n && !n->previousSibling() && (!stayWithin || n->parentNode() != stayWithin))
+ n = n->parentNode();
+ if (n)
+ return n->previousSibling();
+ return 0;
+}
+
+Node* Node::traversePreviousSiblingPostOrder(const Node* stayWithin) const
+{
+ if (this == stayWithin)
+ return 0;
+ if (previousSibling())
+ return previousSibling();
+ const Node *n = this;
+ while (n && !n->previousSibling() && (!stayWithin || n->parentNode() != stayWithin))
+ n = n->parentNode();
+ if (n)
+ return n->previousSibling();
+ return 0;
+}
+
+void Node::checkSetPrefix(const AtomicString &_prefix, ExceptionCode& ec)
+{
+ // Perform error checking as required by spec for setting Node.prefix. Used by
+ // Element::setPrefix() and Attr::setPrefix()
+
+ // FIXME: Implement support for INVALID_CHARACTER_ERR: Raised if the specified prefix contains an illegal character.
+
+ // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+ if (isReadOnlyNode()) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return;
+ }
+
+ // FIXME: Implement NAMESPACE_ERR: - Raised if the specified prefix is malformed
+ // We have to comment this out, since it's used for attributes and tag names, and we've only
+ // switched one over.
+ /*
+ // - if the namespaceURI of this node is null,
+ // - if the specified prefix is "xml" and the namespaceURI of this node is different from
+ // "http://www.w3.org/XML/1998/namespace",
+ // - if this node is an attribute and the specified prefix is "xmlns" and
+ // the namespaceURI of this node is different from "http://www.w3.org/2000/xmlns/",
+ // - or if this node is an attribute and the qualifiedName of this node is "xmlns" [Namespaces].
+ if ((namespacePart(id()) == noNamespace && id() > ID_LAST_TAG) ||
+ (_prefix == "xml" && String(document()->namespaceURI(id())) != "http://www.w3.org/XML/1998/namespace")) {
+ ec = NAMESPACE_ERR;
+ return;
+ }*/
+}
+
+bool Node::canReplaceChild(Node* newChild, Node* oldChild)
+{
+ if (newChild->nodeType() != DOCUMENT_FRAGMENT_NODE) {
+ if (!childTypeAllowed(newChild->nodeType()))
+ return false;
+ }
+ else {
+ for (Node *n = newChild->firstChild(); n; n = n->nextSibling()) {
+ if (!childTypeAllowed(n->nodeType()))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void Node::checkReplaceChild(Node* newChild, Node* oldChild, ExceptionCode& ec)
+{
+ // Perform error checking as required by spec for adding a new child. Used by
+ // appendChild(), replaceChild() and insertBefore()
+
+ // Not mentioned in spec: throw NOT_FOUND_ERR if newChild is null
+ if (!newChild) {
+ ec = NOT_FOUND_ERR;
+ return;
+ }
+
+ // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly
+ if (isReadOnlyNode()) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return;
+ }
+
+ bool shouldAdoptChild = false;
+
+ // WRONG_DOCUMENT_ERR: Raised if newChild was created from a different document than the one that
+ // created this node.
+ // We assume that if newChild is a DocumentFragment, all children are created from the same document
+ // as the fragment itself (otherwise they could not have been added as children)
+ if (newChild->document() != document()) {
+ // but if the child is not in a document yet then loosen the
+ // restriction, so that e.g. creating an element with the Option()
+ // constructor and then adding it to a different document works,
+ // as it does in Mozilla and Mac IE.
+ if (!newChild->inDocument()) {
+ shouldAdoptChild = true;
+ } else {
+ ec = WRONG_DOCUMENT_ERR;
+ return;
+ }
+ }
+
+ // HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not allow children of the type of the
+ // newChild node, or if the node to append is one of this node's ancestors.
+
+ // check for ancestor/same node
+ if (newChild == this || isDescendantOf(newChild)) {
+ ec = HIERARCHY_REQUEST_ERR;
+ return;
+ }
+
+ if (!canReplaceChild(newChild, oldChild)) {
+ ec = HIERARCHY_REQUEST_ERR;
+ return;
+ }
+
+ // change the document pointer of newChild and all of its children to be the new document
+ if (shouldAdoptChild)
+ for (Node* node = newChild; node; node = node->traverseNextNode(newChild))
+ node->setDocument(document());
+}
+
+void Node::checkAddChild(Node *newChild, ExceptionCode& ec)
+{
+ // Perform error checking as required by spec for adding a new child. Used by
+ // appendChild(), replaceChild() and insertBefore()
+
+ // Not mentioned in spec: throw NOT_FOUND_ERR if newChild is null
+ if (!newChild) {
+ ec = NOT_FOUND_ERR;
+ return;
+ }
+
+ // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly
+ if (isReadOnlyNode()) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return;
+ }
+
+ bool shouldAdoptChild = false;
+
+ // WRONG_DOCUMENT_ERR: Raised if newChild was created from a different document than the one that
+ // created this node.
+ // We assume that if newChild is a DocumentFragment, all children are created from the same document
+ // as the fragment itself (otherwise they could not have been added as children)
+ if (newChild->document() != document()) {
+ // but if the child is not in a document yet then loosen the
+ // restriction, so that e.g. creating an element with the Option()
+ // constructor and then adding it to a different document works,
+ // as it does in Mozilla and Mac IE.
+ if (!newChild->inDocument()) {
+ shouldAdoptChild = true;
+ } else {
+ ec = WRONG_DOCUMENT_ERR;
+ return;
+ }
+ }
+
+ // HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not allow children of the type of the
+ // newChild node, or if the node to append is one of this node's ancestors.
+
+ // check for ancestor/same node
+ if (newChild == this || isDescendantOf(newChild)) {
+ ec = HIERARCHY_REQUEST_ERR;
+ return;
+ }
+
+ if (newChild->nodeType() != DOCUMENT_FRAGMENT_NODE) {
+ if (!childTypeAllowed(newChild->nodeType())) {
+ ec = HIERARCHY_REQUEST_ERR;
+ return;
+ }
+ }
+ else {
+ for (Node *n = newChild->firstChild(); n; n = n->nextSibling()) {
+ if (!childTypeAllowed(n->nodeType())) {
+ ec = HIERARCHY_REQUEST_ERR;
+ return;
+ }
+ }
+ }
+
+ // change the document pointer of newChild and all of its children to be the new document
+ if (shouldAdoptChild)
+ for (Node* node = newChild; node; node = node->traverseNextNode(newChild))
+ node->setDocument(document());
+}
+
+bool Node::isDescendantOf(const Node *other) const
+{
+ // Return true if other is an ancestor of this, otherwise false
+ if (!other)
+ return false;
+ for (const Node *n = parentNode(); n; n = n->parentNode()) {
+ if (n == other)
+ return true;
+ }
+ return false;
+}
+
+bool Node::childAllowed(Node* newChild)
+{
+ return childTypeAllowed(newChild->nodeType());
+}
+
+Node::StyleChange Node::diff( RenderStyle *s1, RenderStyle *s2 ) const
+{
+ // FIXME: The behavior of this function is just totally wrong. It doesn't handle
+ // explicit inheritance of non-inherited properties and so you end up not re-resolving
+ // style in cases where you need to.
+ StyleChange ch = NoInherit;
+ EDisplay display1 = s1 ? s1->display() : NONE;
+ bool fl1 = s1 && s1->hasPseudoStyle(RenderStyle::FIRST_LETTER);
+ EDisplay display2 = s2 ? s2->display() : NONE;
+ bool fl2 = s2 && s2->hasPseudoStyle(RenderStyle::FIRST_LETTER);
+
+ if (display1 != display2 || fl1 != fl2 || (s1 && s2 && !s1->contentDataEquivalent(s2)))
+ ch = Detach;
+ else if (!s1 || !s2)
+ ch = Inherit;
+ else if (*s1 == *s2)
+ ch = NoChange;
+ else if (s1->inheritedNotEqual(s2))
+ ch = Inherit;
+
+ // If the pseudoStyles have changed, we want any StyleChange that is not NoChange
+ // because setStyle will do the right thing with anything else.
+ if (ch == NoChange && s1->hasPseudoStyle(RenderStyle::BEFORE)) {
+ RenderStyle* ps2 = s2->getPseudoStyle(RenderStyle::BEFORE);
+ if (!ps2)
+ ch = NoInherit;
+ else {
+ RenderStyle* ps1 = s1->getPseudoStyle(RenderStyle::BEFORE);
+ ch = ps1 && *ps1 == *ps2 ? NoChange : NoInherit;
+ }
+ }
+ if (ch == NoChange && s1->hasPseudoStyle(RenderStyle::AFTER)) {
+ RenderStyle* ps2 = s2->getPseudoStyle(RenderStyle::AFTER);
+ if (!ps2)
+ ch = NoInherit;
+ else {
+ RenderStyle* ps1 = s1->getPseudoStyle(RenderStyle::AFTER);
+ ch = ps2 && *ps1 == *ps2 ? NoChange : NoInherit;
+ }
+ }
+
+ return ch;
+}
+
+void Node::attach()
+{
+ ASSERT(!attached());
+ ASSERT(!renderer() || (renderer()->style() && renderer()->parent()));
+
+ // If this node got a renderer it may be the previousRenderer() of sibling text nodes and thus affect the
+ // result of Text::rendererIsNeeded() for those nodes.
+ if (renderer()) {
+ for (Node* next = nextSibling(); next; next = next->nextSibling()) {
+ if (next->renderer())
+ break;
+ if (!next->attached())
+ break; // Assume this means none of the following siblings are attached.
+ if (next->isTextNode())
+ next->createRendererIfNeeded();
+ }
+ }
+
+ m_attached = true;
+}
+
+void Node::willRemove()
+{
+}
+
+void Node::detach()
+{
+ m_inDetach = true;
+
+ if (renderer())
+ renderer()->destroy();
+ setRenderer(0);
+
+ Document* doc = document();
+ if (m_hovered)
+ doc->hoveredNodeDetached(this);
+ if (m_inActiveChain)
+ doc->activeChainNodeDetached(this);
+
+ m_active = false;
+ m_hovered = false;
+ m_inActiveChain = false;
+ m_attached = false;
+ m_inDetach = false;
+}
+
+void Node::insertedIntoDocument()
+{
+ setInDocument(true);
+ insertedIntoTree(false);
+}
+
+void Node::removedFromDocument()
+{
+ if (m_document && m_document->getCSSTarget() == this)
+ m_document->setCSSTarget(0);
+
+ setInDocument(false);
+ removedFromTree(false);
+}
+
+bool Node::isReadOnlyNode()
+{
+ // Entity & Entity Reference nodes and their descendants are read-only
+ Node *n = this;
+ while (n) {
+ if (n->nodeType() == ENTITY_NODE || n->nodeType() == ENTITY_REFERENCE_NODE)
+ return true;
+ n = n->parentNode();
+ }
+ return false;
+}
+
+Node *Node::previousEditable() const
+{
+ Node *node = previousLeafNode();
+ while (node) {
+ if (node->isContentEditable())
+ return node;
+ node = node->previousLeafNode();
+ }
+ return 0;
+}
+
+// Offset specifies the child node to start at. If it is past
+// the last child, it specifies to start at next sibling.
+Node *Node::nextEditable(int offset) const
+{
+ ASSERT(offset>=0);
+ Node *node;
+ if (hasChildNodes())
+ node = (offset >= (int)childNodeCount()) ? nextSibling() : childNode(offset)->nextLeafNode();
+ else
+ node = nextLeafNode();
+ while (node) {
+ if (node->isContentEditable())
+ return node;
+ node = node->nextLeafNode();
+ }
+ return 0;
+}
+
+Node *Node::nextEditable() const
+{
+ Node *node = nextLeafNode();
+ while (node) {
+ if (node->isContentEditable())
+ return node;
+ node = node->nextLeafNode();
+ }
+ return 0;
+}
+
+RenderObject * Node::previousRenderer()
+{
+ for (Node *n = previousSibling(); n; n = n->previousSibling()) {
+ if (n->renderer())
+ return n->renderer();
+ }
+ return 0;
+}
+
+RenderObject * Node::nextRenderer()
+{
+ // Avoid an O(n^2) problem with this function by not checking for nextRenderer() when the parent element hasn't even
+ // been attached yet.
+ if (parent() && !parent()->attached())
+ return 0;
+
+ for (Node *n = nextSibling(); n; n = n->nextSibling()) {
+ if (n->renderer())
+ return n->renderer();
+ }
+ return 0;
+}
+
+// FIXME: This code is used by editing. Seems like it could move over there and not pollute Node.
+Node *Node::previousNodeConsideringAtomicNodes() const
+{
+ if (previousSibling()) {
+ Node *n = previousSibling();
+ while (!isAtomicNode(n) && n->lastChild())
+ n = n->lastChild();
+ return n;
+ }
+ else if (parentNode()) {
+ return parentNode();
+ }
+ else {
+ return 0;
+ }
+}
+
+Node *Node::nextNodeConsideringAtomicNodes() const
+{
+ if (!isAtomicNode(this) && firstChild())
+ return firstChild();
+ if (nextSibling())
+ return nextSibling();
+ const Node *n = this;
+ while (n && !n->nextSibling())
+ n = n->parentNode();
+ if (n)
+ return n->nextSibling();
+ return 0;
+}
+
+Node *Node::previousLeafNode() const
+{
+ Node *node = previousNodeConsideringAtomicNodes();
+ while (node) {
+ if (isAtomicNode(node))
+ return node;
+ node = node->previousNodeConsideringAtomicNodes();
+ }
+ return 0;
+}
+
+Node *Node::nextLeafNode() const
+{
+ Node *node = nextNodeConsideringAtomicNodes();
+ while (node) {
+ if (isAtomicNode(node))
+ return node;
+ node = node->nextNodeConsideringAtomicNodes();
+ }
+ return 0;
+}
+
+void Node::createRendererIfNeeded()
+{
+ if (!document()->shouldCreateRenderers())
+ return;
+
+ ASSERT(!renderer());
+
+ Node *parent = parentNode();
+ ASSERT(parent);
+
+ RenderObject *parentRenderer = parent->renderer();
+ if (parentRenderer && parentRenderer->canHaveChildren()
+#if ENABLE(SVG)
+ && parent->childShouldCreateRenderer(this)
+#endif
+ ) {
+ RenderStyle* style = styleForRenderer(parentRenderer);
+ if (rendererIsNeeded(style)) {
+ if (RenderObject* r = createRenderer(document()->renderArena(), style)) {
+ if (!parentRenderer->isChildAllowed(r, style))
+ r->destroy();
+ else {
+ setRenderer(r);
+ renderer()->setAnimatableStyle(style);
+ parentRenderer->addChild(renderer(), nextRenderer());
+ }
+ }
+ }
+ style->deref(document()->renderArena());
+ }
+}
+
+RenderStyle *Node::styleForRenderer(RenderObject *parent)
+{
+ RenderStyle *style = parent->style();
+ style->ref();
+ return style;
+}
+
+bool Node::rendererIsNeeded(RenderStyle *style)
+{
+ return (document()->documentElement() == this) || (style->display() != NONE);
+}
+
+RenderObject *Node::createRenderer(RenderArena *arena, RenderStyle *style)
+{
+ ASSERT(false);
+ return 0;
+}
+
+RenderStyle* Node::renderStyle() const
+{
+ return m_renderer ? m_renderer->style() : 0;
+}
+
+void Node::setRenderStyle(RenderStyle* s)
+{
+ if (m_renderer)
+ m_renderer->setAnimatableStyle(s);
+}
+
+RenderStyle* Node::computedStyle()
+{
+ return parent() ? parent()->computedStyle() : 0;
+}
+
+int Node::maxCharacterOffset() const
+{
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+// FIXME: Shouldn't these functions be in the editing code? Code that asks questions about HTML in the core DOM class
+// is obviously misplaced.
+bool Node::canStartSelection() const
+{
+ if (isContentEditable())
+ return true;
+ return parent() ? parent()->canStartSelection() : true;
+}
+
+Node* Node::shadowAncestorNode()
+{
+#if ENABLE(SVG)
+ // SVG elements living in a shadow tree only occour when <use> created them.
+ // For these cases we do NOT want to return the shadowParentNode() here
+ // but the actual shadow tree element - as main difference to the HTML forms
+ // shadow tree concept. (This function _could_ be made virtual - opinions?)
+ if (isSVGElement())
+ return this;
+#endif
+
+ Node *n = this;
+ while (n) {
+ if (n->isShadowNode())
+ return n->shadowParentNode();
+ n = n->parentNode();
+ }
+ return this;
+}
+
+bool Node::isBlockFlow() const
+{
+ return renderer() && renderer()->isBlockFlow();
+}
+
+bool Node::isBlockFlowOrBlockTable() const
+{
+ return renderer() && (renderer()->isBlockFlow() || renderer()->isTable() && !renderer()->isInline());
+}
+
+bool Node::isEditableBlock() const
+{
+ return isContentEditable() && isBlockFlow();
+}
+
+Element *Node::enclosingBlockFlowOrTableElement() const
+{
+ Node *n = const_cast<Node *>(this);
+ if (isBlockFlowOrBlockTable())
+ return static_cast<Element *>(n);
+
+ while (1) {
+ n = n->parentNode();
+ if (!n)
+ break;
+ if (n->isBlockFlowOrBlockTable() || n->hasTagName(bodyTag))
+ return static_cast<Element *>(n);
+ }
+ return 0;
+}
+
+Element *Node::enclosingBlockFlowElement() const
+{
+ Node *n = const_cast<Node *>(this);
+ if (isBlockFlow())
+ return static_cast<Element *>(n);
+
+ while (1) {
+ n = n->parentNode();
+ if (!n)
+ break;
+ if (n->isBlockFlow() || n->hasTagName(bodyTag))
+ return static_cast<Element *>(n);
+ }
+ return 0;
+}
+
+Element *Node::enclosingInlineElement() const
+{
+ Node *n = const_cast<Node *>(this);
+ Node *p;
+
+ while (1) {
+ p = n->parentNode();
+ if (!p || p->isBlockFlow() || p->hasTagName(bodyTag))
+ return static_cast<Element *>(n);
+ // Also stop if any previous sibling is a block
+ for (Node *sibling = n->previousSibling(); sibling; sibling = sibling->previousSibling()) {
+ if (sibling->isBlockFlow())
+ return static_cast<Element *>(n);
+ }
+ n = p;
+ }
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+Element* Node::rootEditableElement() const
+{
+ Element* result = 0;
+ for (Node* n = const_cast<Node*>(this); n && n->isContentEditable(); n = n->parentNode()) {
+ if (n->isElementNode())
+ result = static_cast<Element*>(n);
+ if (n->hasTagName(bodyTag))
+ break;
+ }
+ return result;
+}
+
+bool Node::inSameContainingBlockFlowElement(Node *n)
+{
+ return n ? enclosingBlockFlowElement() == n->enclosingBlockFlowElement() : false;
+}
+
+// FIXME: End of obviously misplaced HTML editing functions. Try to move these out of Node.
+
+PassRefPtr<NodeList> Node::getElementsByTagName(const String& name)
+{
+ return getElementsByTagNameNS("*", name);
+}
+
+PassRefPtr<NodeList> Node::getElementsByTagNameNS(const String& namespaceURI, const String& localName)
+{
+ if (localName.isNull())
+ return 0;
+
+ String name = localName;
+ if (document()->isHTMLDocument())
+ name = localName.lower();
+ return new TagNodeList(this, namespaceURI.isEmpty() ? nullAtom : AtomicString(namespaceURI), name);
+}
+
+PassRefPtr<NodeList> Node::getElementsByName(const String& elementName)
+{
+ if (!m_nodeLists)
+ m_nodeLists.set(new NodeListsNodeData);
+
+ pair<NodeListsNodeData::CacheMap::iterator, bool> result = m_nodeLists->m_nameNodeListCaches.add(elementName, 0);
+ if (result.second)
+ result.first->second = new DynamicNodeList::Caches;
+
+ return new NameNodeList(this, elementName, result.first->second);
+}
+
+PassRefPtr<NodeList> Node::getElementsByClassName(const String& classNames)
+{
+ if (!m_nodeLists)
+ m_nodeLists.set(new NodeListsNodeData);
+
+ pair<NodeListsNodeData::CacheMap::iterator, bool> result = m_nodeLists->m_classNodeListCaches.add(classNames, 0);
+ if (result.second)
+ result.first->second = new DynamicNodeList::Caches;
+
+ return new ClassNodeList(this, classNames, result.first->second);
+}
+
+PassRefPtr<Element> Node::querySelector(const String& selectors, ExceptionCode& ec)
+{
+ if (selectors.isNull() || selectors.isEmpty()) {
+ ec = SYNTAX_ERR;
+ return 0;
+ }
+ CSSStyleSheet tempStyleSheet(document());
+ CSSParser p(true);
+ RefPtr<CSSRule> rule = p.parseRule(&tempStyleSheet, selectors + "{}");
+ if (!rule || !rule->isStyleRule()) {
+ ec = SYNTAX_ERR;
+ return 0;
+ }
+
+ CSSStyleSelector* styleSelector = document()->styleSelector();
+ CSSSelector* querySelector = static_cast<CSSStyleRule*>(rule.get())->selector();
+
+ // FIXME: We can speed this up by implementing caching similar to the one use by getElementById
+ for (Node* n = firstChild(); n; n = n->traverseNextNode(this)) {
+ if (n->isElementNode()) {
+ Element* element = static_cast<Element*>(n);
+ styleSelector->initElementAndPseudoState(element);
+ for (CSSSelector* selector = querySelector; selector; selector = selector->next()) {
+ if (styleSelector->checkSelector(selector))
+ return element;
+ }
+ }
+ }
+
+ return 0;
+}
+
+PassRefPtr<NodeList> Node::querySelectorAll(const String& selectors, ExceptionCode& ec)
+{
+ if (selectors.isNull() || selectors.isEmpty()) {
+ ec = SYNTAX_ERR;
+ return 0;
+ }
+ CSSStyleSheet tempStyleSheet(document());
+ CSSParser p(true);
+ RefPtr<CSSRule> rule = p.parseRule(&tempStyleSheet, selectors + "{}");
+ if (!rule || !rule->isStyleRule()) {
+ ec = SYNTAX_ERR;
+ return 0;
+ }
+
+ SelectorNodeList* resultList = new SelectorNodeList(this, static_cast<CSSStyleRule*>(rule.get())->selector());
+
+ return resultList;
+}
+
+Document *Node::ownerDocument() const
+{
+ Document *doc = document();
+ return doc == this ? 0 : doc;
+}
+
+bool Node::hasAttributes() const
+{
+ return false;
+}
+
+NamedAttrMap* Node::attributes() const
+{
+ return 0;
+}
+
+KURL Node::baseURI() const
+{
+ return parentNode() ? parentNode()->baseURI() : KURL();
+}
+
+bool Node::isEqualNode(Node *other) const
+{
+ if (!other)
+ return false;
+
+ if (nodeType() != other->nodeType())
+ return false;
+
+ if (nodeName() != other->nodeName())
+ return false;
+
+ if (localName() != other->localName())
+ return false;
+
+ if (namespaceURI() != other->namespaceURI())
+ return false;
+
+ if (prefix() != other->prefix())
+ return false;
+
+ if (nodeValue() != other->nodeValue())
+ return false;
+
+ NamedAttrMap *attrs = attributes();
+ NamedAttrMap *otherAttrs = other->attributes();
+
+ if (!attrs && otherAttrs)
+ return false;
+
+ if (attrs && !attrs->mapsEquivalent(otherAttrs))
+ return false;
+
+ Node *child = firstChild();
+ Node *otherChild = other->firstChild();
+
+ while (child) {
+ if (!child->isEqualNode(otherChild))
+ return false;
+
+ child = child->nextSibling();
+ otherChild = otherChild->nextSibling();
+ }
+
+ if (otherChild)
+ return false;
+
+ // FIXME: For DocumentType nodes we should check equality on
+ // the entities and notations NamedNodeMaps as well.
+
+ return true;
+}
+
+bool Node::isDefaultNamespace(const String &namespaceURI) const
+{
+ // Implemented according to
+ // http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/namespaces-algorithms.html#isDefaultNamespaceAlgo
+
+ switch (nodeType()) {
+ case ELEMENT_NODE: {
+ const Element *elem = static_cast<const Element *>(this);
+
+ if (elem->prefix().isNull())
+ return elem->namespaceURI() == namespaceURI;
+
+ if (elem->hasAttributes()) {
+ NamedAttrMap *attrs = elem->attributes();
+
+ for (unsigned i = 0; i < attrs->length(); i++) {
+ Attribute *attr = attrs->attributeItem(i);
+
+ if (attr->localName() == "xmlns")
+ return attr->value() == namespaceURI;
+ }
+ }
+
+ if (Element* ancestor = ancestorElement())
+ return ancestor->isDefaultNamespace(namespaceURI);
+
+ return false;
+ }
+ case DOCUMENT_NODE:
+ return static_cast <const Document *>(this)->documentElement()->isDefaultNamespace(namespaceURI);
+ case ENTITY_NODE:
+ case NOTATION_NODE:
+ case DOCUMENT_TYPE_NODE:
+ case DOCUMENT_FRAGMENT_NODE:
+ return false;
+ case ATTRIBUTE_NODE: {
+ const Attr *attr = static_cast<const Attr *>(this);
+ if (attr->ownerElement())
+ return attr->ownerElement()->isDefaultNamespace(namespaceURI);
+ return false;
+ }
+ default:
+ if (Element* ancestor = ancestorElement())
+ return ancestor->isDefaultNamespace(namespaceURI);
+ return false;
+ }
+}
+
+String Node::lookupPrefix(const String &namespaceURI) const
+{
+ // Implemented according to
+ // http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/namespaces-algorithms.html#lookupNamespacePrefixAlgo
+
+ if (namespaceURI.isEmpty())
+ return String();
+
+ switch (nodeType()) {
+ case ELEMENT_NODE:
+ return lookupNamespacePrefix(namespaceURI, static_cast<const Element *>(this));
+ case DOCUMENT_NODE:
+ return static_cast<const Document *>(this)->documentElement()->lookupPrefix(namespaceURI);
+ case ENTITY_NODE:
+ case NOTATION_NODE:
+ case DOCUMENT_FRAGMENT_NODE:
+ case DOCUMENT_TYPE_NODE:
+ return String();
+ case ATTRIBUTE_NODE: {
+ const Attr *attr = static_cast<const Attr *>(this);
+ if (attr->ownerElement())
+ return attr->ownerElement()->lookupPrefix(namespaceURI);
+ return String();
+ }
+ default:
+ if (Element* ancestor = ancestorElement())
+ return ancestor->lookupPrefix(namespaceURI);
+ return String();
+ }
+}
+
+String Node::lookupNamespaceURI(const String &prefix) const
+{
+ // Implemented according to
+ // http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/namespaces-algorithms.html#lookupNamespaceURIAlgo
+
+ if (!prefix.isNull() && prefix.isEmpty())
+ return String();
+
+ switch (nodeType()) {
+ case ELEMENT_NODE: {
+ const Element *elem = static_cast<const Element *>(this);
+
+ if (!elem->namespaceURI().isNull() && elem->prefix() == prefix)
+ return elem->namespaceURI();
+
+ if (elem->hasAttributes()) {
+ NamedAttrMap *attrs = elem->attributes();
+
+ for (unsigned i = 0; i < attrs->length(); i++) {
+ Attribute *attr = attrs->attributeItem(i);
+
+ if (attr->prefix() == "xmlns" && attr->localName() == prefix) {
+ if (!attr->value().isEmpty())
+ return attr->value();
+
+ return String();
+ } else if (attr->localName() == "xmlns" && prefix.isNull()) {
+ if (!attr->value().isEmpty())
+ return attr->value();
+
+ return String();
+ }
+ }
+ }
+ if (Element* ancestor = ancestorElement())
+ return ancestor->lookupNamespaceURI(prefix);
+ return String();
+ }
+ case DOCUMENT_NODE:
+ return static_cast<const Document *>(this)->documentElement()->lookupNamespaceURI(prefix);
+ case ENTITY_NODE:
+ case NOTATION_NODE:
+ case DOCUMENT_TYPE_NODE:
+ case DOCUMENT_FRAGMENT_NODE:
+ return String();
+ case ATTRIBUTE_NODE: {
+ const Attr *attr = static_cast<const Attr *>(this);
+
+ if (attr->ownerElement())
+ return attr->ownerElement()->lookupNamespaceURI(prefix);
+ else
+ return String();
+ }
+ default:
+ if (Element* ancestor = ancestorElement())
+ return ancestor->lookupNamespaceURI(prefix);
+ return String();
+ }
+}
+
+String Node::lookupNamespacePrefix(const String &_namespaceURI, const Element *originalElement) const
+{
+ if (_namespaceURI.isNull())
+ return String();
+
+ if (originalElement->lookupNamespaceURI(prefix()) == _namespaceURI)
+ return prefix();
+
+ if (hasAttributes()) {
+ NamedAttrMap *attrs = attributes();
+
+ for (unsigned i = 0; i < attrs->length(); i++) {
+ Attribute *attr = attrs->attributeItem(i);
+
+ if (attr->prefix() == "xmlns" &&
+ attr->value() == _namespaceURI &&
+ originalElement->lookupNamespaceURI(attr->localName()) == _namespaceURI)
+ return attr->localName();
+ }
+ }
+
+ if (Element* ancestor = ancestorElement())
+ return ancestor->lookupNamespacePrefix(_namespaceURI, originalElement);
+ return String();
+}
+
+String Node::textContent(bool convertBRsToNewlines) const
+{
+ switch (nodeType()) {
+ case TEXT_NODE:
+ case CDATA_SECTION_NODE:
+ case COMMENT_NODE:
+ case PROCESSING_INSTRUCTION_NODE:
+ return nodeValue();
+
+ case ELEMENT_NODE:
+ if (hasTagName(brTag) &&
+ convertBRsToNewlines)
+ return "\n";
+ case ATTRIBUTE_NODE:
+ case ENTITY_NODE:
+ case ENTITY_REFERENCE_NODE:
+ case DOCUMENT_FRAGMENT_NODE: {
+ String s = "";
+
+ for (Node *child = firstChild(); child; child = child->nextSibling()) {
+ if (child->nodeType() == COMMENT_NODE || child->nodeType() == PROCESSING_INSTRUCTION_NODE)
+ continue;
+
+ s += child->textContent(convertBRsToNewlines);
+ }
+
+ return s;
+ }
+
+ case DOCUMENT_NODE:
+ case DOCUMENT_TYPE_NODE:
+ case NOTATION_NODE:
+ default:
+ return String();
+ }
+}
+
+void Node::setTextContent(const String &text, ExceptionCode& ec)
+{
+ switch (nodeType()) {
+ case TEXT_NODE:
+ case CDATA_SECTION_NODE:
+ case COMMENT_NODE:
+ case PROCESSING_INSTRUCTION_NODE:
+ setNodeValue(text, ec);
+ break;
+ case ELEMENT_NODE:
+ case ATTRIBUTE_NODE:
+ case ENTITY_NODE:
+ case ENTITY_REFERENCE_NODE:
+ case DOCUMENT_FRAGMENT_NODE: {
+ ContainerNode *container = static_cast<ContainerNode *>(this);
+
+ container->removeChildren();
+
+ if (!text.isEmpty())
+ appendChild(document()->createTextNode(text), ec);
+ break;
+ }
+ case DOCUMENT_NODE:
+ case DOCUMENT_TYPE_NODE:
+ case NOTATION_NODE:
+ default:
+ // Do nothing
+ break;
+ }
+}
+
+Element* Node::ancestorElement() const
+{
+ // In theory, there can be EntityReference nodes between elements, but this is currently not supported.
+ for (Node* n = parentNode(); n; n = n->parentNode()) {
+ if (n->isElementNode())
+ return static_cast<Element*>(n);
+ }
+ return 0;
+}
+
+bool Node::offsetInCharacters() const
+{
+ return false;
+}
+
+#ifndef NDEBUG
+
+static void appendAttributeDesc(const Node* node, String& string, const QualifiedName& name, const char* attrDesc)
+{
+ if (node->isElementNode()) {
+ String attr = static_cast<const Element*>(node)->getAttribute(name);
+ if (!attr.isEmpty()) {
+ string += attrDesc;
+ string += attr;
+ }
+ }
+}
+
+void Node::showNode(const char* prefix) const
+{
+ if (!prefix)
+ prefix = "";
+ if (isTextNode()) {
+ String value = nodeValue();
+ value.replace('\\', "\\\\");
+ value.replace('\n', "\\n");
+ fprintf(stderr, "%s%s\t%p \"%s\"\n", prefix, nodeName().utf8().data(), this, value.utf8().data());
+ } else {
+ String attrs = "";
+ appendAttributeDesc(this, attrs, classAttr, " CLASS=");
+ appendAttributeDesc(this, attrs, styleAttr, " STYLE=");
+ fprintf(stderr, "%s%s\t%p%s\n", prefix, nodeName().utf8().data(), this, attrs.utf8().data());
+ }
+}
+
+void Node::showTreeForThis() const
+{
+ showTreeAndMark(this, "*");
+}
+
+void Node::showTreeAndMark(const Node* markedNode1, const char* markedLabel1, const Node* markedNode2, const char * markedLabel2) const
+{
+ const Node* rootNode;
+ const Node* node = this;
+ while (node->parentNode() && !node->hasTagName(bodyTag))
+ node = node->parentNode();
+ rootNode = node;
+
+ for (node = rootNode; node; node = node->traverseNextNode()) {
+ if (node == markedNode1)
+ fprintf(stderr, "%s", markedLabel1);
+ if (node == markedNode2)
+ fprintf(stderr, "%s", markedLabel2);
+
+ for (const Node* tmpNode = node; tmpNode && tmpNode != rootNode; tmpNode = tmpNode->parentNode())
+ fprintf(stderr, "\t");
+ node->showNode();
+ }
+}
+
+void Node::formatForDebugger(char* buffer, unsigned length) const
+{
+ String result;
+ String s;
+
+ s = nodeName();
+ if (s.length() == 0)
+ result += "<none>";
+ else
+ result += s;
+
+ strncpy(buffer, result.utf8().data(), length - 1);
+}
+
+#endif
+
+}
+
+#ifndef NDEBUG
+
+void showTree(const WebCore::Node* node)
+{
+ if (node)
+ node->showTreeForThis();
+}
+
+#endif
diff --git a/WebCore/dom/Node.h b/WebCore/dom/Node.h
new file mode 100644
index 0000000..3abdfc0
--- /dev/null
+++ b/WebCore/dom/Node.h
@@ -0,0 +1,514 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Node_h
+#define Node_h
+
+#include "DocPtr.h"
+#include "PlatformString.h"
+#include "TreeShared.h"
+#include <wtf/Assertions.h>
+#include <wtf/HashSet.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+class AtomicString;
+class ContainerNode;
+class Document;
+class DynamicNodeList;
+class Element;
+class Event;
+class EventListener;
+class IntRect;
+class KeyboardEvent;
+class KURL;
+class NamedAttrMap;
+class NodeList;
+class PlatformKeyboardEvent;
+class PlatformMouseEvent;
+class PlatformWheelEvent;
+class QualifiedName;
+class RegisteredEventListener;
+class RenderArena;
+class RenderObject;
+class RenderStyle;
+
+struct NodeListsNodeData;
+
+typedef int ExceptionCode;
+
+enum StyleChangeType { NoStyleChange, InlineStyleChange, FullStyleChange };
+
+// this class implements nodes, which can have a parent but no children:
+class Node : public TreeShared<Node> {
+ friend class Document;
+public:
+ enum NodeType {
+ ELEMENT_NODE = 1,
+ ATTRIBUTE_NODE = 2,
+ TEXT_NODE = 3,
+ CDATA_SECTION_NODE = 4,
+ ENTITY_REFERENCE_NODE = 5,
+ ENTITY_NODE = 6,
+ PROCESSING_INSTRUCTION_NODE = 7,
+ COMMENT_NODE = 8,
+ DOCUMENT_NODE = 9,
+ DOCUMENT_TYPE_NODE = 10,
+ DOCUMENT_FRAGMENT_NODE = 11,
+ NOTATION_NODE = 12,
+ XPATH_NAMESPACE_NODE = 13
+ };
+
+ static bool isSupported(const String& feature, const String& version);
+
+ static void startIgnoringLeaks();
+ static void stopIgnoringLeaks();
+
+ Node(Document*);
+ virtual ~Node();
+
+ // DOM methods & attributes for Node
+
+ bool hasTagName(const QualifiedName& name) const { return virtualHasTagName(name); }
+ virtual String nodeName() const = 0;
+ virtual String nodeValue() const;
+ virtual void setNodeValue(const String&, ExceptionCode&);
+ virtual NodeType nodeType() const = 0;
+ Node* parentNode() const { return parent(); }
+ Node* parentElement() const { return parent(); } // IE extension
+ Node* previousSibling() const { return m_previous; }
+ Node* nextSibling() const { return m_next; }
+ virtual PassRefPtr<NodeList> childNodes();
+ Node* firstChild() const { return virtualFirstChild(); }
+ Node* lastChild() const { return virtualLastChild(); }
+ virtual bool hasAttributes() const;
+ virtual NamedAttrMap* attributes() const;
+
+ virtual KURL baseURI() const;
+
+ // These should all actually return a node, but this is only important for language bindings,
+ // which will already know and hold a ref on the right node to return. Returning bool allows
+ // these methods to be more efficient since they don't need to return a ref
+ virtual bool insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionCode&);
+ virtual bool replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionCode&);
+ virtual bool removeChild(Node* child, ExceptionCode&);
+ virtual bool appendChild(PassRefPtr<Node> newChild, ExceptionCode&);
+
+ virtual void remove(ExceptionCode&);
+ virtual bool hasChildNodes() const;
+ virtual PassRefPtr<Node> cloneNode(bool deep) = 0;
+ virtual const AtomicString& localName() const;
+ virtual const AtomicString& namespaceURI() const;
+ virtual const AtomicString& prefix() const;
+ virtual void setPrefix(const AtomicString&, ExceptionCode&);
+ void normalize();
+
+ bool isSameNode(Node* other) const { return this == other; }
+ bool isEqualNode(Node*) const;
+ bool isDefaultNamespace(const String& namespaceURI) const;
+ String lookupPrefix(const String& namespaceURI) const;
+ String lookupNamespaceURI(const String& prefix) const;
+ String lookupNamespacePrefix(const String& namespaceURI, const Element* originalElement) const;
+
+ String textContent(bool convertBRsToNewlines = false) const;
+ void setTextContent(const String&, ExceptionCode&);
+
+ Node* lastDescendant() const;
+ Node* firstDescendant() const;
+
+ // Other methods (not part of DOM)
+
+ virtual bool isElementNode() const { return false; }
+ virtual bool isHTMLElement() const { return false; }
+
+#if ENABLE(SVG)
+ virtual
+#endif
+ bool isSVGElement() const { return false; }
+
+ virtual bool isStyledElement() const { return false; }
+ virtual bool isFrameOwnerElement() const { return false; }
+ virtual bool isAttributeNode() const { return false; }
+ virtual bool isTextNode() const { return false; }
+ virtual bool isCommentNode() const { return false; }
+ virtual bool isCharacterDataNode() const { return false; }
+ virtual bool isDocumentNode() const { return false; }
+ virtual bool isEventTargetNode() const { return false; }
+ virtual bool isShadowNode() const { return false; }
+ virtual Node* shadowParentNode() { return 0; }
+ Node* shadowAncestorNode();
+
+ // The node's parent for the purpose of event capture and bubbling.
+ virtual Node* eventParentNode() { return parentNode(); }
+
+ bool isBlockFlow() const;
+ bool isBlockFlowOrBlockTable() const;
+
+ // Used by <form> elements to indicate a malformed state of some kind, typically
+ // used to keep from applying the bottom margin of the form.
+ virtual bool isMalformed() { return false; }
+ virtual void setMalformed(bool malformed) { }
+
+ // These low-level calls give the caller responsibility for maintaining the integrity of the tree.
+ void setPreviousSibling(Node* previous) { m_previous = previous; }
+ void setNextSibling(Node* next) { m_next = next; }
+
+ // FIXME: These two functions belong in editing -- "atomic node" is an editing concept.
+ Node* previousNodeConsideringAtomicNodes() const;
+ Node* nextNodeConsideringAtomicNodes() const;
+
+ /** (Not part of the official DOM)
+ * Returns the next leaf node.
+ *
+ * Using this function delivers leaf nodes as if the whole DOM tree were a linear chain of its leaf nodes.
+ * @return next leaf node or 0 if there are no more.
+ */
+ Node* nextLeafNode() const;
+
+ /** (Not part of the official DOM)
+ * Returns the previous leaf node.
+ *
+ * Using this function delivers leaf nodes as if the whole DOM tree were a linear chain of its leaf nodes.
+ * @return previous leaf node or 0 if there are no more.
+ */
+ Node* previousLeafNode() const;
+
+ bool isEditableBlock() const;
+ Element* enclosingBlockFlowElement() const;
+ Element* enclosingBlockFlowOrTableElement() const;
+ Element* enclosingInlineElement() const;
+ Element* rootEditableElement() const;
+
+ bool inSameContainingBlockFlowElement(Node*);
+
+ // Used by the parser. Checks against the DTD, unlike DOM operations like appendChild().
+ // Also does not dispatch DOM mutation events.
+ // Returns the appropriate container node for future insertions as you parse, or 0 for failure.
+ virtual ContainerNode* addChild(PassRefPtr<Node>);
+
+ // Called by the parser when this element's close tag is reached,
+ // signalling that all child tags have been parsed and added.
+ // This is needed for <applet> and <object> elements, which can't lay themselves out
+ // until they know all of their nested <param>s. [Radar 3603191, 4040848].
+ // Also used for script elements and some SVG elements for similar purposes,
+ // but making parsing a special case in this respect should be avoided if possible.
+ virtual void finishParsingChildren() { }
+ virtual void beginParsingChildren() { }
+
+ // Called by the frame right before dispatching an unloadEvent. [Radar 4532113]
+ // This is needed for HTMLInputElements to tell the frame that it is done editing
+ // (sends textFieldDidEndEditing notification)
+ virtual void aboutToUnload() { }
+
+ // For <link> and <style> elements.
+ virtual bool sheetLoaded() { return true; }
+
+ bool hasID() const { return m_hasId; }
+ bool hasClass() const { return m_hasClass; }
+ bool active() const { return m_active; }
+ bool inActiveChain() const { return m_inActiveChain; }
+ bool inDetach() const { return m_inDetach; }
+ bool hovered() const { return m_hovered; }
+ bool focused() const { return m_focused; }
+ bool attached() const { return m_attached; }
+ void setAttached(bool b = true) { m_attached = b; }
+ bool changed() const { return m_styleChange != NoStyleChange; }
+ StyleChangeType styleChangeType() const { return static_cast<StyleChangeType>(m_styleChange); }
+ bool hasChangedChild() const { return m_hasChangedChild; }
+ bool isLink() const { return m_isLink; }
+ void setHasID(bool b = true) { m_hasId = b; }
+ void setHasClass(bool b = true) { m_hasClass = b; }
+ void setHasChangedChild( bool b = true ) { m_hasChangedChild = b; }
+ void setInDocument(bool b = true) { m_inDocument = b; }
+ void setInActiveChain(bool b = true) { m_inActiveChain = b; }
+ void setChanged(StyleChangeType changeType = FullStyleChange);
+
+ virtual void setFocus(bool b = true) { m_focused = b; }
+ virtual void setActive(bool b = true, bool pause=false) { m_active = b; }
+ virtual void setHovered(bool b = true) { m_hovered = b; }
+
+ short tabIndex() const { return m_tabIndex; }
+ void setTabIndex(short i) { m_tabIndex = i; }
+
+ /**
+ * Whether this node can receive the keyboard focus.
+ */
+ virtual bool supportsFocus() const { return isFocusable(); }
+ virtual bool isFocusable() const;
+ virtual bool isKeyboardFocusable(KeyboardEvent*) const;
+ virtual bool isMouseFocusable() const;
+
+ virtual bool isControl() const { return false; } // Eventually the notion of what is a control will be extensible.
+ virtual bool isEnabled() const { return true; }
+ virtual bool isChecked() const { return false; }
+ virtual bool isIndeterminate() const { return false; }
+ virtual bool isReadOnlyControl() const { return false; }
+
+ virtual bool isContentEditable() const;
+ virtual bool isContentRichlyEditable() const;
+ virtual bool shouldUseInputMethod() const;
+ virtual IntRect getRect() const;
+
+ enum StyleChange { NoChange, NoInherit, Inherit, Detach, Force };
+ virtual void recalcStyle(StyleChange = NoChange) { }
+ StyleChange diff(RenderStyle*, RenderStyle*) const;
+
+ unsigned nodeIndex() const;
+
+ // Returns the DOM ownerDocument attribute. This method never returns NULL, except in the case
+ // of (1) a Document node or (2) a DocumentType node that is not used with any Document yet.
+ virtual Document* ownerDocument() const;
+
+ // Returns the document associated with this node. This method never returns NULL, except in the case
+ // of a DocumentType node that is not used with any Document yet. A Document node returns itself.
+ Document* document() const
+ {
+ ASSERT(this);
+ ASSERT(m_document || nodeType() == DOCUMENT_TYPE_NODE && !inDocument());
+ return m_document.get();
+ }
+ void setDocument(Document*);
+
+ // Returns true if this node is associated with a document and is in its associated document's
+ // node tree, false otherwise.
+ bool inDocument() const
+ {
+ ASSERT(m_document || !m_inDocument);
+ return m_inDocument;
+ }
+
+ virtual bool isReadOnlyNode();
+ virtual bool childTypeAllowed(NodeType) { return false; }
+ virtual unsigned childNodeCount() const;
+ virtual Node* childNode(unsigned index) const;
+
+ /**
+ * Does a pre-order traversal of the tree to find the node next node after this one. This uses the same order that
+ * the tags appear in the source file.
+ *
+ * @param stayWithin If not null, the traversal will stop once the specified node is reached. This can be used to
+ * restrict traversal to a particular sub-tree.
+ *
+ * @return The next node, in document order
+ *
+ * see @ref traversePreviousNode()
+ */
+ Node* traverseNextNode(const Node* stayWithin = 0) const;
+
+ /* Like traverseNextNode, but skips children and starts with the next sibling. */
+ Node* traverseNextSibling(const Node* stayWithin = 0) const;
+
+ /**
+ * Does a reverse pre-order traversal to find the node that comes before the current one in document order
+ *
+ * see @ref traverseNextNode()
+ */
+ Node* traversePreviousNode(const Node * stayWithin = 0) const;
+
+ /* Like traversePreviousNode, but visits nodes before their children. */
+ Node* traversePreviousNodePostOrder(const Node *stayWithin = 0) const;
+ Node* traversePreviousSiblingPostOrder(const Node *stayWithin = 0) const;
+
+ /**
+ * Finds previous or next editable leaf node.
+ */
+ Node* previousEditable() const;
+ Node* nextEditable() const;
+ Node* nextEditable(int offset) const;
+
+ RenderObject* renderer() const { return m_renderer; }
+ RenderObject* nextRenderer();
+ RenderObject* previousRenderer();
+ void setRenderer(RenderObject* renderer) { m_renderer = renderer; }
+
+ void checkSetPrefix(const AtomicString& prefix, ExceptionCode&);
+ bool isDescendantOf(const Node*) const;
+
+ // These two methods are mutually exclusive. The former is used to do strict error-checking
+ // when adding children via the public DOM API (e.g., appendChild()). The latter is called only when parsing,
+ // to sanity-check against the DTD for error recovery.
+ void checkAddChild(Node* newChild, ExceptionCode&); // Error-checking when adding via the DOM API
+ virtual bool childAllowed(Node* newChild); // Error-checking during parsing that checks the DTD
+
+ void checkReplaceChild(Node* newChild, Node* oldChild, ExceptionCode&);
+ virtual bool canReplaceChild(Node* newChild, Node* oldChild);
+
+ // Used to determine whether range offsets use characters or node indices.
+ virtual bool offsetInCharacters() const;
+ // Number of DOM 16-bit units contained in node. Note that rendered text length can be different - e.g. because of
+ // css-transform:capitalize breaking up precomposed characters and ligatures.
+ virtual int maxCharacterOffset() const;
+
+ // FIXME: We should try to find a better location for these methods.
+ virtual bool canSelectAll() const { return false; }
+ virtual void selectAll() { }
+
+ // Whether or not a selection can be started in this object
+ virtual bool canStartSelection() const;
+
+ // -----------------------------------------------------------------------------
+ // Integration with rendering tree
+
+ /**
+ * Attaches this node to the rendering tree. This calculates the style to be applied to the node and creates an
+ * appropriate RenderObject which will be inserted into the tree (except when the style has display: none). This
+ * makes the node visible in the FrameView.
+ */
+ virtual void attach();
+
+ /**
+ * Detaches the node from the rendering tree, making it invisible in the rendered view. This method will remove
+ * the node's rendering object from the rendering tree and delete it.
+ */
+ virtual void detach();
+
+ virtual void willRemove();
+ void createRendererIfNeeded();
+ virtual RenderStyle* styleForRenderer(RenderObject* parent);
+ virtual bool rendererIsNeeded(RenderStyle*);
+#if ENABLE(SVG)
+ virtual bool childShouldCreateRenderer(Node*) const { return true; }
+#endif
+ virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+
+ // Wrapper for nodes that don't have a renderer, but still cache the style (like HTMLOptionElement).
+ virtual RenderStyle* renderStyle() const;
+ virtual void setRenderStyle(RenderStyle*);
+
+ virtual RenderStyle* computedStyle();
+
+ // -----------------------------------------------------------------------------
+ // Notification of document structure changes
+
+ /**
+ * Notifies the node that it has been inserted into the document. This is called during document parsing, and also
+ * when a node is added through the DOM methods insertBefore(), appendChild() or replaceChild(). Note that this only
+ * happens when the node becomes part of the document tree, i.e. only when the document is actually an ancestor of
+ * the node. The call happens _after_ the node has been added to the tree.
+ *
+ * This is similar to the DOMNodeInsertedIntoDocument DOM event, but does not require the overhead of event
+ * dispatching.
+ */
+ virtual void insertedIntoDocument();
+
+ /**
+ * Notifies the node that it is no longer part of the document tree, i.e. when the document is no longer an ancestor
+ * node.
+ *
+ * This is similar to the DOMNodeRemovedFromDocument DOM event, but does not require the overhead of event
+ * dispatching, and is called _after_ the node is removed from the tree.
+ */
+ virtual void removedFromDocument();
+
+ // These functions are called whenever you are connected or disconnected from a tree. That tree may be the main
+ // document tree, or it could be another disconnected tree. Override these functions to do any work that depends
+ // on connectedness to some ancestor (e.g., an ancestor <form> for example).
+ virtual void insertedIntoTree(bool deep) { }
+ virtual void removedFromTree(bool deep) { }
+
+ /**
+ * Notifies the node that it's list of children have changed (either by adding or removing child nodes), or a child
+ * node that is of the type CDATA_SECTION_NODE, TEXT_NODE or COMMENT_NODE has changed its value.
+ */
+ virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0) {};
+
+ virtual String toString() const = 0;
+
+#ifndef NDEBUG
+ virtual void formatForDebugger(char* buffer, unsigned length) const;
+
+ void showNode(const char* prefix = "") const;
+ void showTreeForThis() const;
+ void showTreeAndMark(const Node* markedNode1, const char* markedLabel1, const Node* markedNode2 = 0, const char* markedLabel2 = 0) const;
+#endif
+
+ void registerDynamicNodeList(DynamicNodeList*);
+ void unregisterDynamicNodeList(DynamicNodeList*);
+ void notifyNodeListsChildrenChanged();
+ void notifyLocalNodeListsChildrenChanged();
+ void notifyNodeListsAttributeChanged();
+ void notifyLocalNodeListsAttributeChanged();
+
+ PassRefPtr<NodeList> getElementsByTagName(const String&);
+ PassRefPtr<NodeList> getElementsByTagNameNS(const String& namespaceURI, const String& localName);
+ PassRefPtr<NodeList> getElementsByName(const String& elementName);
+ PassRefPtr<NodeList> getElementsByClassName(const String& classNames);
+
+ PassRefPtr<Element> querySelector(const String& selectors, ExceptionCode&);
+ PassRefPtr<NodeList> querySelectorAll(const String& selectors, ExceptionCode&);
+
+private: // members
+ DocPtr<Document> m_document;
+ Node* m_previous;
+ Node* m_next;
+ RenderObject* m_renderer;
+
+protected:
+ virtual void willMoveToNewOwnerDocument() { }
+ virtual void didMoveToNewOwnerDocument() { }
+
+ OwnPtr<NodeListsNodeData> m_nodeLists;
+
+ short m_tabIndex;
+
+ // make sure we don't use more than 16 bits here -- adding more would increase the size of all Nodes
+
+ bool m_hasId : 1;
+ bool m_hasClass : 1;
+ bool m_attached : 1;
+ unsigned m_styleChange : 2;
+ bool m_hasChangedChild : 1;
+ bool m_inDocument : 1;
+
+ bool m_isLink : 1;
+ bool m_attrWasSpecifiedOrElementHasRareData : 1; // used in Attr for one thing and Element for another
+ bool m_focused : 1;
+ bool m_active : 1;
+ bool m_hovered : 1;
+ bool m_inActiveChain : 1;
+
+ bool m_inDetach : 1;
+ bool m_dispatchingSimulatedEvent : 1;
+
+public:
+ bool m_inSubtreeMark : 1;
+ // 0 bits left
+
+private:
+ Element* ancestorElement() const;
+
+ virtual Node* virtualFirstChild() const;
+ virtual Node* virtualLastChild() const;
+ virtual bool virtualHasTagName(const QualifiedName&) const;
+};
+
+} //namespace
+
+#ifndef NDEBUG
+// Outside the WebCore namespace for ease of invocation from gdb.
+void showTree(const WebCore::Node*);
+#endif
+
+#endif
diff --git a/WebCore/dom/Node.idl b/WebCore/dom/Node.idl
new file mode 100644
index 0000000..c6af454
--- /dev/null
+++ b/WebCore/dom/Node.idl
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module core {
+
+ interface [
+ CustomMarkFunction,
+ GenerateConstructor,
+ GenerateNativeConverter,
+ GenerateToJS,
+ ObjCCustomInternalImpl,
+ InterfaceUUID=84BA0D7A-7E3E-4a7b-B6FB-7653E8FB54ED,
+ ImplementationUUID=81B47FDB-94B0-40fd-8E0C-FB2A6E53CC04
+ ] Node {
+ // NodeType
+ const unsigned short ELEMENT_NODE = 1;
+ const unsigned short ATTRIBUTE_NODE = 2;
+ const unsigned short TEXT_NODE = 3;
+ const unsigned short CDATA_SECTION_NODE = 4;
+ const unsigned short ENTITY_REFERENCE_NODE = 5;
+ const unsigned short ENTITY_NODE = 6;
+ const unsigned short PROCESSING_INSTRUCTION_NODE = 7;
+ const unsigned short COMMENT_NODE = 8;
+ const unsigned short DOCUMENT_NODE = 9;
+ const unsigned short DOCUMENT_TYPE_NODE = 10;
+ const unsigned short DOCUMENT_FRAGMENT_NODE = 11;
+ const unsigned short NOTATION_NODE = 12;
+
+ readonly attribute [ConvertNullStringTo=Null] DOMString nodeName;
+
+ // FIXME: the spec says this can also raise on retrieval.
+ attribute [ConvertNullStringTo=Null, ConvertNullToNullString] DOMString nodeValue
+ setter raises(DOMException);
+
+ readonly attribute unsigned short nodeType;
+ readonly attribute Node parentNode;
+ readonly attribute NodeList childNodes;
+ readonly attribute Node firstChild;
+ readonly attribute Node lastChild;
+ readonly attribute Node previousSibling;
+ readonly attribute Node nextSibling;
+ readonly attribute NamedNodeMap attributes;
+ readonly attribute Document ownerDocument;
+
+ [OldStyleObjC, Custom] Node insertBefore(in [Return] Node newChild,
+ in Node refChild)
+ raises(DOMException);
+ [OldStyleObjC, Custom] Node replaceChild(in Node newChild,
+ in [Return] Node oldChild)
+ raises(DOMException);
+ [Custom] Node removeChild(in [Return] Node oldChild)
+ raises(DOMException);
+ [Custom] Node appendChild(in [Return] Node newChild)
+ raises(DOMException);
+
+ boolean hasChildNodes();
+ Node cloneNode(in boolean deep);
+ void normalize();
+
+ // Introduced in DOM Level 2:
+
+ [OldStyleObjC] boolean isSupported(in DOMString feature,
+ in [ConvertNullToNullString] DOMString version);
+
+ readonly attribute [ConvertNullStringTo=Null] DOMString namespaceURI;
+ attribute [ConvertNullStringTo=Null, ConvertNullToNullString] DOMString prefix
+ setter raises(DOMException);
+ readonly attribute [ConvertNullStringTo=Null] DOMString localName;
+
+ boolean hasAttributes();
+
+ // Introduced in DOM Level 3:
+
+ readonly attribute [ConvertNullStringTo=Null] DOMString baseURI;
+
+ // FIXME: the spec says this can also raise on retrieval.
+ attribute [ConvertNullStringTo=Null, ConvertNullToNullString] DOMString textContent
+ setter raises(DOMException);
+
+ boolean isSameNode(in Node other);
+ boolean isEqualNode(in Node other);
+ [ConvertNullStringTo=Null] DOMString lookupPrefix(in [ConvertNullToNullString] DOMString namespaceURI);
+ boolean isDefaultNamespace(in [ConvertNullToNullString] DOMString namespaceURI);
+ [ConvertNullStringTo=Null] DOMString lookupNamespaceURI(in [ConvertNullToNullString] DOMString prefix);
+
+#if 0
+ // DocumentPosition
+ const unsigned short DOCUMENT_POSITION_DISCONNECTED = 0x01;
+ const unsigned short DOCUMENT_POSITION_PRECEDING = 0x02;
+ const unsigned short DOCUMENT_POSITION_FOLLOWING = 0x04;
+ const unsigned short DOCUMENT_POSITION_CONTAINS = 0x08;
+ const unsigned short DOCUMENT_POSITION_CONTAINED_BY = 0x10;
+ const unsigned short DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20;
+
+ unsigned short compareDocumentPosition(in Node other)
+ raises(DOMException);
+
+ DOMObject getFeature(in DOMString feature,
+ in DOMString version);
+ DOMUserData setUserData(in DOMString key,
+ in DOMUserData data,
+ in UserDataHandler handler);
+ DOMUserData getUserData(in DOMString key);
+#endif /* 0 */
+
+ // IE extentions
+ readonly attribute Node parentElement;
+
+#if defined(LANGUAGE_OBJECTIVE_C)
+ // Objective-C extensions
+ readonly attribute boolean isContentEditable;
+#endif /* defined(LANGUAGE_OBJECTIVE_C) */
+ };
+
+}
diff --git a/WebCore/dom/NodeFilter.cpp b/WebCore/dom/NodeFilter.cpp
new file mode 100644
index 0000000..1844a2d
--- /dev/null
+++ b/WebCore/dom/NodeFilter.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "NodeFilter.h"
+
+using namespace KJS;
+
+namespace WebCore {
+
+short NodeFilter::acceptNode(Node* node, JSValue*& exception) const
+{
+ // cast to short silences "enumeral and non-enumeral types in return" warning
+ return m_condition ? m_condition->acceptNode(node, exception) : static_cast<short>(FILTER_ACCEPT);
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/NodeFilter.h b/WebCore/dom/NodeFilter.h
new file mode 100644
index 0000000..2f7c822
--- /dev/null
+++ b/WebCore/dom/NodeFilter.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef NodeFilter_h
+#define NodeFilter_h
+
+#include "NodeFilterCondition.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+ class NodeFilter : public RefCounted<NodeFilter> {
+ public:
+ /**
+ * The following constants are returned by the acceptNode()
+ * method:
+ */
+ enum {
+ FILTER_ACCEPT = 1,
+ FILTER_REJECT = 2,
+ FILTER_SKIP = 3
+ };
+
+ /**
+ * These are the available values for the whatToShow parameter.
+ * They are the same as the set of possible types for Node, and
+ * their values are derived by using a bit position corresponding
+ * to the value of NodeType for the equivalent node type.
+ */
+ enum {
+ SHOW_ALL = 0xFFFFFFFF,
+ SHOW_ELEMENT = 0x00000001,
+ SHOW_ATTRIBUTE = 0x00000002,
+ SHOW_TEXT = 0x00000004,
+ SHOW_CDATA_SECTION = 0x00000008,
+ SHOW_ENTITY_REFERENCE = 0x00000010,
+ SHOW_ENTITY = 0x00000020,
+ SHOW_PROCESSING_INSTRUCTION = 0x00000040,
+ SHOW_COMMENT = 0x00000080,
+ SHOW_DOCUMENT = 0x00000100,
+ SHOW_DOCUMENT_TYPE = 0x00000200,
+ SHOW_DOCUMENT_FRAGMENT = 0x00000400,
+ SHOW_NOTATION = 0x00000800
+ };
+
+ NodeFilter(PassRefPtr<NodeFilterCondition> condition) : RefCounted<NodeFilter>(0), m_condition(condition) { }
+ short acceptNode(Node*, KJS::JSValue*& exception) const;
+ void mark() { m_condition->mark(); };
+
+ // For non-JS bindings. Silently ignores the JavaScript exception if any.
+ short acceptNode(Node* node) const { KJS::JSValue* exception; return acceptNode(node, exception); }
+
+ private:
+ RefPtr<NodeFilterCondition> m_condition;
+ };
+
+} // namespace WebCore
+
+#endif // NodeFilter_h
diff --git a/WebCore/dom/NodeFilter.idl b/WebCore/dom/NodeFilter.idl
new file mode 100644
index 0000000..3cc5e86
--- /dev/null
+++ b/WebCore/dom/NodeFilter.idl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module traversal {
+
+ // Introduced in DOM Level 2:
+ interface [GenerateConstructor, CustomMarkFunction, CustomNativeConverter, ObjCProtocol] NodeFilter {
+
+ // Constants returned by acceptNode
+ const short FILTER_ACCEPT = 1;
+ const short FILTER_REJECT = 2;
+ const short FILTER_SKIP = 3;
+
+ // Constants for whatToShow
+ const unsigned long SHOW_ALL = 0xFFFFFFFF;
+ const unsigned long SHOW_ELEMENT = 0x00000001;
+ const unsigned long SHOW_ATTRIBUTE = 0x00000002;
+ const unsigned long SHOW_TEXT = 0x00000004;
+ const unsigned long SHOW_CDATA_SECTION = 0x00000008;
+ const unsigned long SHOW_ENTITY_REFERENCE = 0x00000010;
+ const unsigned long SHOW_ENTITY = 0x00000020;
+ const unsigned long SHOW_PROCESSING_INSTRUCTION = 0x00000040;
+ const unsigned long SHOW_COMMENT = 0x00000080;
+ const unsigned long SHOW_DOCUMENT = 0x00000100;
+ const unsigned long SHOW_DOCUMENT_TYPE = 0x00000200;
+ const unsigned long SHOW_DOCUMENT_FRAGMENT = 0x00000400;
+ const unsigned long SHOW_NOTATION = 0x00000800;
+
+ [Custom] short acceptNode(in Node n);
+
+ };
+
+}
diff --git a/WebCore/dom/NodeFilterCondition.cpp b/WebCore/dom/NodeFilterCondition.cpp
new file mode 100644
index 0000000..48bdcb4
--- /dev/null
+++ b/WebCore/dom/NodeFilterCondition.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "NodeFilterCondition.h"
+
+#include "NodeFilter.h"
+
+using namespace KJS;
+
+namespace WebCore {
+
+short NodeFilterCondition::acceptNode(Node*, JSValue*&) const
+{
+ return NodeFilter::FILTER_ACCEPT;
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/NodeFilterCondition.h b/WebCore/dom/NodeFilterCondition.h
new file mode 100644
index 0000000..7596684
--- /dev/null
+++ b/WebCore/dom/NodeFilterCondition.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef NodeFilterCondition_h
+#define NodeFilterCondition_h
+
+#include <wtf/RefCounted.h>
+
+namespace KJS {
+ class JSValue;
+}
+
+namespace WebCore {
+
+ class Node;
+
+ class NodeFilterCondition : public RefCounted<NodeFilterCondition> {
+ public:
+ NodeFilterCondition() : RefCounted<NodeFilterCondition>(0) { }
+ virtual ~NodeFilterCondition() { }
+ virtual short acceptNode(Node*, KJS::JSValue*& exception) const;
+ virtual void mark() { }
+ };
+
+} // namespace WebCore
+
+#endif // NodeFilterCondition_h
diff --git a/WebCore/dom/NodeIterator.cpp b/WebCore/dom/NodeIterator.cpp
new file mode 100644
index 0000000..502d393
--- /dev/null
+++ b/WebCore/dom/NodeIterator.cpp
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "NodeIterator.h"
+
+#include "Document.h"
+#include "ExceptionCode.h"
+#include "NodeFilter.h"
+
+using namespace KJS;
+
+namespace WebCore {
+
+NodeIterator::NodePointer::NodePointer()
+{
+}
+
+NodeIterator::NodePointer::NodePointer(PassRefPtr<Node> n, bool b)
+ : node(n)
+ , isPointerBeforeNode(b)
+{
+}
+
+void NodeIterator::NodePointer::clear()
+{
+ node.clear();
+}
+
+bool NodeIterator::NodePointer::moveToNext(Node* root)
+{
+ if (!node)
+ return false;
+ if (isPointerBeforeNode) {
+ isPointerBeforeNode = false;
+ return true;
+ }
+ node = node->traverseNextNode(root);
+ return node;
+}
+
+bool NodeIterator::NodePointer::moveToPrevious(Node* root)
+{
+ if (!node)
+ return false;
+ if (!isPointerBeforeNode) {
+ isPointerBeforeNode = true;
+ return true;
+ }
+ node = node->traversePreviousNode(root);
+ return node;
+}
+
+NodeIterator::NodeIterator(PassRefPtr<Node> rootNode, unsigned whatToShow, PassRefPtr<NodeFilter> filter, bool expandEntityReferences)
+ : Traversal(rootNode, whatToShow, filter, expandEntityReferences)
+ , m_referenceNode(root(), true)
+ , m_detached(false)
+{
+ root()->document()->attachNodeIterator(this);
+}
+
+NodeIterator::~NodeIterator()
+{
+ root()->document()->detachNodeIterator(this);
+}
+
+Node* NodeIterator::nextNode(ExceptionCode& ec, JSValue*& exception)
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return 0;
+ }
+
+ Node* result = 0;
+
+ m_candidateNode = m_referenceNode;
+ while (m_candidateNode.moveToNext(root())) {
+ // NodeIterators treat the DOM tree as a flat list of nodes.
+ // In other words, FILTER_REJECT does not pass over descendants
+ // of the rejected node. Hence, FILTER_REJECT is the same as FILTER_SKIP.
+ exception = 0;
+ bool nodeWasAccepted = acceptNode(m_candidateNode.node.get(), exception) == NodeFilter::FILTER_ACCEPT;
+ if (exception)
+ break;
+ if (nodeWasAccepted) {
+ m_referenceNode = m_candidateNode;
+ result = m_referenceNode.node.get();
+ break;
+ }
+ }
+
+ m_candidateNode.clear();
+ return result;
+}
+
+Node* NodeIterator::previousNode(ExceptionCode& ec, JSValue*& exception)
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return 0;
+ }
+
+ Node* result = 0;
+
+ m_candidateNode = m_referenceNode;
+ while (m_candidateNode.moveToPrevious(root())) {
+ // NodeIterators treat the DOM tree as a flat list of nodes.
+ // In other words, FILTER_REJECT does not pass over descendants
+ // of the rejected node. Hence, FILTER_REJECT is the same as FILTER_SKIP.
+ exception = 0;
+ bool nodeWasAccepted = acceptNode(m_candidateNode.node.get(), exception) == NodeFilter::FILTER_ACCEPT;
+ if (exception)
+ break;
+ if (nodeWasAccepted) {
+ m_referenceNode = m_candidateNode;
+ result = m_referenceNode.node.get();
+ break;
+ }
+ }
+
+ m_candidateNode.clear();
+ return result;
+}
+
+void NodeIterator::detach()
+{
+ root()->document()->detachNodeIterator(this);
+ m_detached = true;
+ m_referenceNode.node.clear();
+}
+
+void NodeIterator::notifyBeforeNodeRemoval(Node* removedNode)
+{
+ updateForNodeRemoval(removedNode, m_referenceNode);
+}
+
+void NodeIterator::updateForNodeRemoval(Node* removedNode, NodePointer& referenceNode) const
+{
+ ASSERT(!m_detached);
+ ASSERT(removedNode);
+ ASSERT(root()->document() == removedNode->document());
+
+ // Iterator is not affected if the removed node is the reference node and is the root.
+ // or if removed node is not the reference node, or the ancestor of the reference node.
+ if (!removedNode->isDescendantOf(root()))
+ return;
+ bool willRemoveReferenceNode = removedNode == referenceNode.node;
+ bool willRemoveReferenceNodeAncestor = referenceNode.node && referenceNode.node->isDescendantOf(removedNode);
+ if (!willRemoveReferenceNode && !willRemoveReferenceNodeAncestor)
+ return;
+
+ if (referenceNode.isPointerBeforeNode) {
+ Node* node = removedNode->traverseNextNode(root());
+ if (node) {
+ // Move out from under the node being removed if the reference node is
+ // a descendant of the node being removed.
+ if (willRemoveReferenceNodeAncestor) {
+ while (node && node->isDescendantOf(removedNode))
+ node = node->traverseNextNode(root());
+ }
+ if (node)
+ referenceNode.node = node;
+ } else {
+ node = removedNode->traversePreviousNode(root());
+ if (node) {
+ // Move out from under the node being removed if the reference node is
+ // a descendant of the node being removed.
+ if (willRemoveReferenceNodeAncestor) {
+ while (node && node->isDescendantOf(removedNode))
+ node = node->traversePreviousNode(root());
+ }
+ if (node) {
+ // Removing last node.
+ // Need to move the pointer after the node preceding the
+ // new reference node.
+ referenceNode.node = node;
+ referenceNode.isPointerBeforeNode = false;
+ }
+ }
+ }
+ } else {
+ Node* node = removedNode->traversePreviousNode(root());
+ if (node) {
+ // Move out from under the node being removed if the reference node is
+ // a descendant of the node being removed.
+ if (willRemoveReferenceNodeAncestor) {
+ while (node && node->isDescendantOf(removedNode))
+ node = node->traversePreviousNode(root());
+ }
+ if (node)
+ referenceNode.node = node;
+ } else {
+ node = removedNode->traverseNextNode(root());
+ // Move out from under the node being removed if the reference node is
+ // a descendant of the node being removed.
+ if (willRemoveReferenceNodeAncestor) {
+ while (node && node->isDescendantOf(removedNode))
+ node = node->traversePreviousNode(root());
+ }
+ if (node)
+ referenceNode.node = node;
+ }
+ }
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/NodeIterator.h b/WebCore/dom/NodeIterator.h
new file mode 100644
index 0000000..b2a7c70
--- /dev/null
+++ b/WebCore/dom/NodeIterator.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef NodeIterator_h
+#define NodeIterator_h
+
+#include "Traversal.h"
+#include <wtf/PassRefPtr.h>
+
+namespace WebCore {
+
+ typedef int ExceptionCode;
+
+ class NodeIterator : public Traversal {
+ public:
+ NodeIterator(PassRefPtr<Node>, unsigned whatToShow, PassRefPtr<NodeFilter>, bool expandEntityReferences);
+ virtual ~NodeIterator();
+
+ Node* nextNode(ExceptionCode&, KJS::JSValue*& exception);
+ Node* previousNode(ExceptionCode&, KJS::JSValue*& exception);
+ void detach();
+
+ Node* referenceNode() const { return m_referenceNode.node.get(); }
+ bool pointerBeforeReferenceNode() const { return m_referenceNode.isPointerBeforeNode; }
+
+ // This function is called before any node is removed from the document tree.
+ void notifyBeforeNodeRemoval(Node* nodeToBeRemoved);
+
+ // For non-JS bindings. Silently ignores the JavaScript exception if any.
+ Node* nextNode(ExceptionCode& ec) { KJS::JSValue* exception; return nextNode(ec, exception); }
+ Node* previousNode(ExceptionCode& ec) { KJS::JSValue* exception; return previousNode(ec, exception); }
+
+ private:
+ struct NodePointer {
+ RefPtr<Node> node;
+ bool isPointerBeforeNode;
+ NodePointer();
+ NodePointer(PassRefPtr<Node>, bool);
+ void clear();
+ bool moveToNext(Node* root);
+ bool moveToPrevious(Node* root);
+ };
+
+ void updateForNodeRemoval(Node* nodeToBeRemoved, NodePointer&) const;
+
+ NodePointer m_referenceNode;
+ NodePointer m_candidateNode;
+ bool m_detached;
+ };
+
+} // namespace WebCore
+
+#endif // NodeIterator_h
diff --git a/WebCore/dom/NodeIterator.idl b/WebCore/dom/NodeIterator.idl
new file mode 100644
index 0000000..e129de3
--- /dev/null
+++ b/WebCore/dom/NodeIterator.idl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module traversal {
+
+ // Introduced in DOM Level 2:
+ interface [CustomMarkFunction] NodeIterator {
+ readonly attribute Node root;
+ readonly attribute unsigned long whatToShow;
+ readonly attribute [ObjCIvar] NodeFilter filter;
+ readonly attribute boolean expandEntityReferences;
+ readonly attribute Node referenceNode;
+ readonly attribute boolean pointerBeforeReferenceNode;
+
+ [Custom] Node nextNode()
+ raises (DOMException);
+ [Custom] Node previousNode()
+ raises (DOMException);
+ void detach();
+ };
+
+}
diff --git a/WebCore/dom/NodeList.h b/WebCore/dom/NodeList.h
new file mode 100644
index 0000000..2bc1443
--- /dev/null
+++ b/WebCore/dom/NodeList.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef NodeList_h
+#define NodeList_h
+
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+ class AtomicString;
+ class Node;
+
+ class NodeList : public RefCounted<NodeList> {
+ public:
+ NodeList() : RefCounted<NodeList>(0) { }
+ virtual ~NodeList() { }
+
+ // DOM methods & attributes for NodeList
+ virtual unsigned length() const = 0;
+ virtual Node* item(unsigned index) const = 0;
+ virtual Node* itemWithName(const AtomicString&) const = 0;
+ };
+
+} // namespace WebCore
+
+#endif // NodeList_h
diff --git a/WebCore/dom/NodeList.idl b/WebCore/dom/NodeList.idl
new file mode 100644
index 0000000..cf21cc7
--- /dev/null
+++ b/WebCore/dom/NodeList.idl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module core {
+
+ interface [
+ GenerateConstructor,
+ HasIndexGetter,
+ HasNameGetter,
+ CustomCall,
+ InterfaceUUID=F9A9F6A9-385C-414e-A6F6-E2E0CF574130,
+ ImplementationUUID=BBB49E8B-DB1D-4c4a-B970-D300FB4609FA
+ ] NodeList {
+
+ Node item(in [IsIndex] unsigned long index);
+
+ readonly attribute unsigned long length;
+
+ };
+
+}
diff --git a/WebCore/dom/Notation.cpp b/WebCore/dom/Notation.cpp
new file mode 100644
index 0000000..7081d98
--- /dev/null
+++ b/WebCore/dom/Notation.cpp
@@ -0,0 +1,61 @@
+/**
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2000 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#include "config.h"
+#include "Notation.h"
+
+namespace WebCore {
+
+Notation::Notation(Document* doc) : ContainerNode(doc)
+{
+}
+
+Notation::Notation(Document* doc, const String& name, const String& publicId, const String& systemId)
+ : ContainerNode(doc)
+ , m_name(name)
+ , m_publicId(publicId)
+ , m_systemId(systemId)
+{
+}
+
+String Notation::nodeName() const
+{
+ return m_name;
+}
+
+Node::NodeType Notation::nodeType() const
+{
+ return NOTATION_NODE;
+}
+
+PassRefPtr<Node> Notation::cloneNode(bool /*deep*/)
+{
+ // Spec says cloning Notation nodes is "implementation dependent". We do not support it.
+ return 0;
+}
+
+// DOM Section 1.1.1
+bool Notation::childTypeAllowed(NodeType)
+{
+ return false;
+}
+
+} // namespace
diff --git a/WebCore/dom/Notation.h b/WebCore/dom/Notation.h
new file mode 100644
index 0000000..6f5bf3f
--- /dev/null
+++ b/WebCore/dom/Notation.h
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2000 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Notation_h
+#define Notation_h
+
+#include "CachedResourceClient.h"
+#include "ContainerNode.h"
+
+namespace WebCore {
+
+class Notation : public ContainerNode
+{
+public:
+ Notation(Document*);
+ Notation(Document*, const String& name, const String& publicId, const String& systemId);
+
+ // DOM methods & attributes for Notation
+ String publicId() const { return m_publicId; }
+ String systemId() const { return m_systemId; }
+
+ virtual String nodeName() const;
+ virtual NodeType nodeType() const;
+ virtual PassRefPtr<Node> cloneNode(bool deep);
+ virtual bool childTypeAllowed(NodeType);
+
+private:
+ String m_name;
+ String m_publicId;
+ String m_systemId;
+};
+
+} //namespace
+
+#endif
diff --git a/WebCore/dom/Notation.idl b/WebCore/dom/Notation.idl
new file mode 100644
index 0000000..a16fde6
--- /dev/null
+++ b/WebCore/dom/Notation.idl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module core {
+
+ interface [
+ GenerateConstructor,
+ InterfaceUUID=6580C703-F5FF-40a7-ACF2-AB80EBC83CA1,
+ ImplementationUUID=A52869F7-A3CE-4f4c-8C27-E369C4ED9FF9
+ ] Notation : Node {
+ readonly attribute [ConvertNullStringTo=Null] DOMString publicId;
+ readonly attribute [ConvertNullStringTo=Null] DOMString systemId;
+ };
+
+}
diff --git a/WebCore/dom/OverflowEvent.cpp b/WebCore/dom/OverflowEvent.cpp
new file mode 100644
index 0000000..b32213d
--- /dev/null
+++ b/WebCore/dom/OverflowEvent.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2006, 2007 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "OverflowEvent.h"
+
+#include "EventNames.h"
+
+namespace WebCore {
+
+using namespace EventNames;
+
+OverflowEvent::OverflowEvent()
+ : Event(overflowchangedEvent, false, false)
+ , m_orient(VERTICAL)
+ , m_horizontalOverflow(false)
+ , m_verticalOverflow(false)
+{
+}
+
+OverflowEvent::OverflowEvent(bool horizontalOverflowChanged, bool horizontalOverflow, bool verticalOverflowChanged, bool verticalOverflow)
+ : Event(overflowchangedEvent, false, false)
+ , m_horizontalOverflow(horizontalOverflow)
+ , m_verticalOverflow(verticalOverflow)
+{
+ ASSERT(horizontalOverflowChanged || verticalOverflowChanged);
+
+ if (horizontalOverflowChanged && verticalOverflowChanged)
+ m_orient = BOTH;
+ else if (horizontalOverflowChanged)
+ m_orient = HORIZONTAL;
+ else
+ m_orient = VERTICAL;
+}
+
+bool OverflowEvent::isOverflowEvent() const
+{
+ return true;
+}
+
+void OverflowEvent::initOverflowEvent(unsigned short orient, bool horizontalOverflow, bool verticalOverflow)
+{
+ if (dispatched())
+ return;
+
+ m_orient = orient;
+ m_horizontalOverflow = horizontalOverflow;
+ m_verticalOverflow = verticalOverflow;
+}
+
+}
diff --git a/WebCore/dom/OverflowEvent.h b/WebCore/dom/OverflowEvent.h
new file mode 100644
index 0000000..fb3e289
--- /dev/null
+++ b/WebCore/dom/OverflowEvent.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2006, 2007 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 OverflowEvent_h
+#define OverflowEvent_h
+
+#include "Event.h"
+
+namespace WebCore {
+
+ class OverflowEvent : public Event {
+ public:
+ enum orientType {
+ VERTICAL = 0,
+ HORIZONTAL = 1,
+ BOTH = 2
+ };
+
+ OverflowEvent();
+ OverflowEvent(bool horizontalOverflowChanged, bool horizontalOverflow, bool verticalOverflowChanged, bool verticalOverflow);
+
+ void initOverflowEvent(unsigned short orient, bool horizontalOverflow, bool verticalOverflow);
+
+ unsigned short orient() const { return m_orient; }
+ bool horizontalOverflow() const { return m_horizontalOverflow; }
+ bool verticalOverflow() const { return m_verticalOverflow; }
+
+ virtual bool isOverflowEvent() const;
+
+ private:
+ unsigned short m_orient;
+ bool m_horizontalOverflow;
+ bool m_verticalOverflow;
+ };
+}
+
+#endif // OverflowEvent_h
+
diff --git a/WebCore/dom/OverflowEvent.idl b/WebCore/dom/OverflowEvent.idl
new file mode 100644
index 0000000..4a1bed5
--- /dev/null
+++ b/WebCore/dom/OverflowEvent.idl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2006, 2007 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+module events {
+
+ interface [
+ GenerateConstructor
+ ] OverflowEvent : Event {
+ const unsigned short HORIZONTAL = 0;
+ const unsigned short VERTICAL = 1;
+ const unsigned short BOTH = 2;
+
+ readonly attribute unsigned short orient;
+ readonly attribute boolean horizontalOverflow;
+ readonly attribute boolean verticalOverflow;
+
+ void initOverflowEvent(in unsigned short orient,
+ in boolean horizontalOverflow,
+ in boolean verticalOverflow);
+ };
+
+}
diff --git a/WebCore/dom/Position.cpp b/WebCore/dom/Position.cpp
new file mode 100644
index 0000000..84ff856
--- /dev/null
+++ b/WebCore/dom/Position.cpp
@@ -0,0 +1,763 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "Position.h"
+
+#include "CSSComputedStyleDeclaration.h"
+#include "CString.h"
+#include "CharacterNames.h"
+#include "Document.h"
+#include "Element.h"
+#include "HTMLNames.h"
+#include "Logging.h"
+#include "PositionIterator.h"
+#include "RenderBlock.h"
+#include "Text.h"
+#include "TextIterator.h"
+#include "htmlediting.h"
+#include "visible_units.h"
+#include <stdio.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+static Node *nextRenderedEditable(Node *node)
+{
+ while (1) {
+ node = node->nextEditable();
+ if (!node)
+ return 0;
+ if (!node->renderer())
+ continue;
+ if (node->renderer()->inlineBox(0))
+ return node;
+ }
+ return 0;
+}
+
+static Node *previousRenderedEditable(Node *node)
+{
+ while (1) {
+ node = node->previousEditable();
+ if (!node)
+ return 0;
+ if (!node->renderer())
+ continue;
+ if (node->renderer()->inlineBox(0))
+ return node;
+ }
+ return 0;
+}
+
+Position::Position(Node* node, int offset)
+ : m_node(node)
+ , m_offset(offset)
+{
+}
+
+Position::Position(const PositionIterator& it)
+ : m_node(it.m_parent)
+ , m_offset(it.m_child ? it.m_child->nodeIndex() : (it.m_parent->hasChildNodes() ? maxDeepOffset(it.m_parent) : it.m_offset))
+{
+}
+
+void Position::clear()
+{
+ m_node = 0;
+ m_offset = 0;
+}
+
+Element* Position::documentElement() const
+{
+ if (Node* n = node())
+ if (Element* e = n->document()->documentElement())
+ return e;
+ return 0;
+}
+
+Element *Position::element() const
+{
+ Node *n;
+ for (n = node(); n && !n->isElementNode(); n = n->parentNode())
+ ; // empty loop body
+ return static_cast<Element *>(n);
+}
+
+PassRefPtr<CSSComputedStyleDeclaration> Position::computedStyle() const
+{
+ Element *elem = element();
+ if (!elem)
+ return 0;
+ return new CSSComputedStyleDeclaration(elem);
+}
+
+Position Position::previous(EUsingComposedCharacters usingComposedCharacters) const
+{
+ Node *n = node();
+ if (!n)
+ return *this;
+
+ int o = offset();
+ // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier.
+ ASSERT(o >= 0);
+
+ if (o > 0) {
+ Node *child = n->childNode(o - 1);
+ if (child) {
+ return Position(child, maxDeepOffset(child));
+ }
+ // There are two reasons child might be 0:
+ // 1) The node is node like a text node that is not an element, and therefore has no children.
+ // Going backward one character at a time is correct.
+ // 2) The old offset was a bogus offset like (<br>, 1), and there is no child.
+ // Going from 1 to 0 is correct.
+ return Position(n, usingComposedCharacters ? uncheckedPreviousOffset(n, o) : o - 1);
+ }
+
+ Node *parent = n->parentNode();
+ if (!parent)
+ return *this;
+
+ return Position(parent, n->nodeIndex());
+}
+
+Position Position::next(EUsingComposedCharacters usingComposedCharacters) const
+{
+ Node *n = node();
+ if (!n)
+ return *this;
+
+ int o = offset();
+ // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier.
+ ASSERT(o >= 0);
+
+ Node* child = n->childNode(o);
+ if (child || !n->hasChildNodes() && o < maxDeepOffset(n)) {
+ if (child)
+ return Position(child, 0);
+
+ // There are two reasons child might be 0:
+ // 1) The node is node like a text node that is not an element, and therefore has no children.
+ // Going forward one character at a time is correct.
+ // 2) The new offset is a bogus offset like (<br>, 1), and there is no child.
+ // Going from 0 to 1 is correct.
+ return Position(n, usingComposedCharacters ? uncheckedNextOffset(n, o) : o + 1);
+ }
+
+ Node *parent = n->parentNode();
+ if (!parent)
+ return *this;
+
+ return Position(parent, n->nodeIndex() + 1);
+}
+
+int Position::uncheckedPreviousOffset(const Node* n, int current)
+{
+ return n->renderer() ? n->renderer()->previousOffset(current) : current - 1;
+}
+
+int Position::uncheckedNextOffset(const Node* n, int current)
+{
+ return n->renderer() ? n->renderer()->nextOffset(current) : current + 1;
+}
+
+bool Position::atStart() const
+{
+ Node *n = node();
+ if (!n)
+ return true;
+
+ return offset() <= 0 && n->parent() == 0;
+}
+
+bool Position::atEnd() const
+{
+ Node *n = node();
+ if (!n)
+ return true;
+
+ return n->parent() == 0 && offset() >= maxDeepOffset(n);
+}
+
+int Position::renderedOffset() const
+{
+ if (!node()->isTextNode())
+ return offset();
+
+ if (!node()->renderer())
+ return offset();
+
+ int result = 0;
+ RenderText *textRenderer = static_cast<RenderText *>(node()->renderer());
+ for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
+ int start = box->m_start;
+ int end = box->m_start + box->m_len;
+ if (offset() < start)
+ return result;
+ if (offset() <= end) {
+ result += offset() - start;
+ return result;
+ }
+ result += box->m_len;
+ }
+ return result;
+}
+
+// return first preceding DOM position rendered at a different location, or "this"
+Position Position::previousCharacterPosition(EAffinity affinity) const
+{
+ if (isNull())
+ return Position();
+
+ Node *fromRootEditableElement = node()->rootEditableElement();
+
+ bool atStartOfLine = isStartOfLine(VisiblePosition(*this, affinity));
+ bool rendered = isCandidate();
+
+ Position currentPos = *this;
+ while (!currentPos.atStart()) {
+ currentPos = currentPos.previous();
+
+ if (currentPos.node()->rootEditableElement() != fromRootEditableElement)
+ return *this;
+
+ if (atStartOfLine || !rendered) {
+ if (currentPos.isCandidate())
+ return currentPos;
+ } else if (rendersInDifferentPosition(currentPos))
+ return currentPos;
+ }
+
+ return *this;
+}
+
+// return first following position rendered at a different location, or "this"
+Position Position::nextCharacterPosition(EAffinity affinity) const
+{
+ if (isNull())
+ return Position();
+
+ Node *fromRootEditableElement = node()->rootEditableElement();
+
+ bool atEndOfLine = isEndOfLine(VisiblePosition(*this, affinity));
+ bool rendered = isCandidate();
+
+ Position currentPos = *this;
+ while (!currentPos.atEnd()) {
+ currentPos = currentPos.next();
+
+ if (currentPos.node()->rootEditableElement() != fromRootEditableElement)
+ return *this;
+
+ if (atEndOfLine || !rendered) {
+ if (currentPos.isCandidate())
+ return currentPos;
+ } else if (rendersInDifferentPosition(currentPos))
+ return currentPos;
+ }
+
+ return *this;
+}
+
+// upstream() and downstream() want to return positions that are either in a
+// text node or at just before a non-text node. This method checks for that.
+static bool isStreamer(const PositionIterator& pos)
+{
+ if (!pos.node())
+ return true;
+
+ if (isAtomicNode(pos.node()))
+ return true;
+
+ return pos.atStartOfNode();
+}
+
+// enclosingBlock does some expensive editability checks, upstream and downstream
+// can avoid those because they do their own editability checking.
+static Node* enclosingBlockIgnoringEditability(Node* node)
+{
+ while (node && !isBlock(node))
+ node = node->parentNode();
+
+ return node;
+}
+
+// p.upstream() returns the start of the range of positions that map to the same VisiblePosition as P.
+Position Position::upstream() const
+{
+ Node* startNode = node();
+ if (!startNode)
+ return Position();
+
+ // iterate backward from there, looking for a qualified position
+ Node* originalBlock = enclosingBlockIgnoringEditability(startNode);
+ PositionIterator lastVisible = *this;
+ PositionIterator currentPos = lastVisible;
+ bool startEditable = startNode->isContentEditable();
+ Node* lastNode = startNode;
+ for (; !currentPos.atStart(); currentPos.decrement()) {
+ Node* currentNode = currentPos.node();
+
+ // Don't check for an editability change if we haven't moved to a different node,
+ // to avoid the expense of computing isContentEditable().
+ if (currentNode != lastNode) {
+ // Don't change editability.
+ bool currentEditable = currentNode->isContentEditable();
+ if (startEditable != currentEditable)
+ break;
+ lastNode = currentNode;
+ }
+
+ // Don't enter a new enclosing block flow or table element. There is code below that
+ // terminates early if we're about to leave a block.
+ if (isBlock(currentNode) && currentNode != originalBlock)
+ return lastVisible;
+
+ // skip position in unrendered or invisible node
+ RenderObject* renderer = currentNode->renderer();
+ if (!renderer || renderer->style()->visibility() != VISIBLE)
+ continue;
+
+ // track last visible streamer position
+ if (isStreamer(currentPos))
+ lastVisible = currentPos;
+
+ // Don't leave a block flow or table element. We could rely on code above to terminate and
+ // return lastVisible on the next iteration, but we terminate early to avoid doing a nodeIndex() call.
+ if (isBlock(currentNode) && currentPos.atStartOfNode())
+ return lastVisible;
+
+ // Return position after tables and nodes which have content that can be ignored.
+ if (editingIgnoresContent(currentNode) || isTableElement(currentNode)) {
+ if (currentPos.atEndOfNode())
+ return Position(currentNode, maxDeepOffset(currentNode));
+ continue;
+ }
+
+ // return current position if it is in rendered text
+ if (renderer->isText() && static_cast<RenderText*>(renderer)->firstTextBox()) {
+ if (currentNode != startNode) {
+ // This assertion fires in layout tests in the case-transform.html test because
+ // of a mix-up between offsets in the text in the DOM tree with text in the
+ // render tree which can have a different length due to case transformation.
+ // Until we resolve that, disable this so we can run the layout tests!
+ //ASSERT(currentOffset >= renderer->caretMaxOffset());
+ return Position(currentNode, renderer->caretMaxOffset());
+ }
+
+ unsigned textOffset = currentPos.offsetInLeafNode();
+ RenderText* textRenderer = static_cast<RenderText*>(renderer);
+ for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
+ if (textOffset > box->start() && textOffset <= box->start() + box->len())
+ return currentPos;
+
+ if (box != textRenderer->lastTextBox() &&
+ !box->nextOnLine() &&
+ textOffset == box->start() + box->len() + 1)
+ return currentPos;
+ }
+ }
+ }
+
+ return lastVisible;
+}
+
+// P.downstream() returns the end of the range of positions that map to the same VisiblePosition as P.
+Position Position::downstream() const
+{
+ Node* startNode = node();
+ if (!startNode)
+ return Position();
+
+ // iterate forward from there, looking for a qualified position
+ Node* originalBlock = enclosingBlockIgnoringEditability(startNode);
+ PositionIterator lastVisible = *this;
+ PositionIterator currentPos = lastVisible;
+ bool startEditable = startNode->isContentEditable();
+ Node* lastNode = startNode;
+ for (; !currentPos.atEnd(); currentPos.increment()) {
+ Node* currentNode = currentPos.node();
+
+ // Don't check for an editability change if we haven't moved to a different node,
+ // to avoid the expense of computing isContentEditable().
+ if (currentNode != lastNode) {
+ // Don't change editability.
+ bool currentEditable = currentNode->isContentEditable();
+ if (startEditable != currentEditable)
+ break;
+ lastNode = currentNode;
+ }
+
+ // stop before going above the body, up into the head
+ // return the last visible streamer position
+ if (currentNode->hasTagName(bodyTag) && currentPos.atEndOfNode())
+ break;
+
+ // Do not enter a new enclosing block.
+ if (isBlock(currentNode) && currentNode != originalBlock)
+ return lastVisible;
+ // Do not leave the original enclosing block.
+ // Note: The first position after the last one in the original block
+ // will be [originalBlock->parentNode(), originalBlock->nodeIndex() + 1].
+ if (originalBlock && originalBlock->parentNode() == currentNode)
+ return lastVisible;
+
+ // skip position in unrendered or invisible node
+ RenderObject* renderer = currentNode->renderer();
+ if (!renderer || renderer->style()->visibility() != VISIBLE)
+ continue;
+
+ // track last visible streamer position
+ if (isStreamer(currentPos))
+ lastVisible = currentPos;
+
+ // Return position before tables and nodes which have content that can be ignored.
+ if (editingIgnoresContent(currentNode) || isTableElement(currentNode)) {
+ if (currentPos.offsetInLeafNode() <= renderer->caretMinOffset())
+ return Position(currentNode, renderer->caretMinOffset());
+ continue;
+ }
+
+ // return current position if it is in rendered text
+ if (renderer->isText() && static_cast<RenderText*>(renderer)->firstTextBox()) {
+ if (currentNode != startNode) {
+ ASSERT(currentPos.atStartOfNode());
+ return Position(currentNode, renderer->caretMinOffset());
+ }
+
+ unsigned textOffset = currentPos.offsetInLeafNode();
+
+ RenderText* textRenderer = static_cast<RenderText*>(renderer);
+ for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
+ if (textOffset >= box->start() && textOffset <= box->end())
+ return currentPos;
+
+ if (box != textRenderer->lastTextBox() &&
+ !box->nextOnLine() &&
+ textOffset == box->start() + box->len()) {
+ return currentPos;
+ }
+ }
+ }
+ }
+
+ return lastVisible;
+}
+
+bool Position::hasRenderedNonAnonymousDescendantsWithHeight(RenderObject* renderer)
+{
+ RenderObject* stop = renderer->nextInPreOrderAfterChildren();
+ for (RenderObject *o = renderer->firstChild(); o && o != stop; o = o->nextInPreOrder())
+ if (o->element() && o->height())
+ return true;
+
+ return false;
+}
+
+bool Position::nodeIsUserSelectNone(Node* node)
+{
+ return node && node->renderer() && node->renderer()->style()->userSelect() == SELECT_NONE;
+}
+
+bool Position::isCandidate() const
+{
+ if (isNull())
+ return false;
+
+ RenderObject *renderer = node()->renderer();
+ if (!renderer)
+ return false;
+
+ if (renderer->style()->visibility() != VISIBLE)
+ return false;
+
+ if (renderer->isBR())
+ return offset() == 0 && !nodeIsUserSelectNone(node()->parent());
+
+ if (renderer->isText())
+ return inRenderedText() && !nodeIsUserSelectNone(node());
+
+ if (isTableElement(node()) || editingIgnoresContent(node()))
+ return (offset() == 0 || offset() == maxDeepOffset(node())) && !nodeIsUserSelectNone(node()->parent());
+
+ if (!node()->hasTagName(htmlTag) && renderer->isBlockFlow() && !hasRenderedNonAnonymousDescendantsWithHeight(renderer) &&
+ (renderer->height() || node()->hasTagName(bodyTag)))
+ return offset() == 0 && !nodeIsUserSelectNone(node());
+
+ return false;
+}
+
+bool Position::inRenderedText() const
+{
+ if (isNull() || !node()->isTextNode())
+ return false;
+
+ RenderObject *renderer = node()->renderer();
+ if (!renderer)
+ return false;
+
+ RenderText *textRenderer = static_cast<RenderText *>(renderer);
+ for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
+ if (offset() < box->m_start && !textRenderer->containsReversedText()) {
+ // The offset we're looking for is before this node
+ // this means the offset must be in content that is
+ // not rendered. Return false.
+ return false;
+ }
+ if (box->containsCaretOffset(offset()))
+ // Return false for offsets inside composed characters.
+ return offset() == 0 || offset() == textRenderer->nextOffset(textRenderer->previousOffset(offset()));
+ }
+
+ return false;
+}
+
+static unsigned caretMaxRenderedOffset(const Node* n)
+{
+ RenderObject* r = n->renderer();
+ if (r)
+ return r->caretMaxRenderedOffset();
+
+ if (n->isCharacterDataNode())
+ return static_cast<const CharacterData*>(n)->length();
+ return 1;
+}
+
+bool Position::isRenderedCharacter() const
+{
+ if (isNull() || !node()->isTextNode())
+ return false;
+
+ RenderObject *renderer = node()->renderer();
+ if (!renderer)
+ return false;
+
+ RenderText *textRenderer = static_cast<RenderText *>(renderer);
+ for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
+ if (offset() < box->m_start && !textRenderer->containsReversedText()) {
+ // The offset we're looking for is before this node
+ // this means the offset must be in content that is
+ // not rendered. Return false.
+ return false;
+ }
+ if (offset() >= box->m_start && offset() < box->m_start + box->m_len)
+ return true;
+ }
+
+ return false;
+}
+
+bool Position::rendersInDifferentPosition(const Position &pos) const
+{
+ if (isNull() || pos.isNull())
+ return false;
+
+ RenderObject *renderer = node()->renderer();
+ if (!renderer)
+ return false;
+
+ RenderObject *posRenderer = pos.node()->renderer();
+ if (!posRenderer)
+ return false;
+
+ if (renderer->style()->visibility() != VISIBLE ||
+ posRenderer->style()->visibility() != VISIBLE)
+ return false;
+
+ if (node() == pos.node()) {
+ if (node()->hasTagName(brTag))
+ return false;
+
+ if (offset() == pos.offset())
+ return false;
+
+ if (!node()->isTextNode() && !pos.node()->isTextNode()) {
+ if (offset() != pos.offset())
+ return true;
+ }
+ }
+
+ if (node()->hasTagName(brTag) && pos.isCandidate())
+ return true;
+
+ if (pos.node()->hasTagName(brTag) && isCandidate())
+ return true;
+
+ if (node()->enclosingBlockFlowElement() != pos.node()->enclosingBlockFlowElement())
+ return true;
+
+ if (node()->isTextNode() && !inRenderedText())
+ return false;
+
+ if (pos.node()->isTextNode() && !pos.inRenderedText())
+ return false;
+
+ int thisRenderedOffset = renderedOffset();
+ int posRenderedOffset = pos.renderedOffset();
+
+ if (renderer == posRenderer && thisRenderedOffset == posRenderedOffset)
+ return false;
+
+ LOG(Editing, "renderer: %p [%p]\n", renderer, renderer ? renderer->inlineBox(offset()) : 0);
+ LOG(Editing, "thisRenderedOffset: %d\n", thisRenderedOffset);
+ LOG(Editing, "posRenderer: %p [%p]\n", posRenderer, posRenderer ? posRenderer->inlineBox(offset()) : 0);
+ LOG(Editing, "posRenderedOffset: %d\n", posRenderedOffset);
+ LOG(Editing, "node min/max: %d:%d\n", caretMinOffset(node()), caretMaxRenderedOffset(node()));
+ LOG(Editing, "pos node min/max: %d:%d\n", caretMinOffset(pos.node()), caretMaxRenderedOffset(pos.node()));
+ LOG(Editing, "----------------------------------------------------------------------\n");
+
+ InlineBox *b1 = renderer ? renderer->inlineBox(offset()) : 0;
+ InlineBox *b2 = posRenderer ? posRenderer->inlineBox(pos.offset()) : 0;
+
+ if (!b1 || !b2) {
+ return false;
+ }
+
+ if (b1->root() != b2->root()) {
+ return true;
+ }
+
+ if (nextRenderedEditable(node()) == pos.node() &&
+ thisRenderedOffset == (int)caretMaxRenderedOffset(node()) && posRenderedOffset == 0) {
+ return false;
+ }
+
+ if (previousRenderedEditable(node()) == pos.node() &&
+ thisRenderedOffset == 0 && posRenderedOffset == (int)caretMaxRenderedOffset(pos.node())) {
+ return false;
+ }
+
+ return true;
+}
+
+// This assumes that it starts in editable content.
+Position Position::leadingWhitespacePosition(EAffinity affinity, bool considerNonCollapsibleWhitespace) const
+{
+ ASSERT(isEditablePosition(*this));
+ if (isNull())
+ return Position();
+
+ if (upstream().node()->hasTagName(brTag))
+ return Position();
+
+ Position prev = previousCharacterPosition(affinity);
+ if (prev != *this && prev.node()->inSameContainingBlockFlowElement(node()) && prev.node()->isTextNode()) {
+ String string = static_cast<Text *>(prev.node())->data();
+ UChar c = string[prev.offset()];
+ if (considerNonCollapsibleWhitespace ? (isSpaceOrNewline(c) || c == noBreakSpace) : isCollapsibleWhitespace(c))
+ if (isEditablePosition(prev))
+ return prev;
+ }
+
+ return Position();
+}
+
+// This assumes that it starts in editable content.
+Position Position::trailingWhitespacePosition(EAffinity affinity, bool considerNonCollapsibleWhitespace) const
+{
+ ASSERT(isEditablePosition(*this));
+ if (isNull())
+ return Position();
+
+ VisiblePosition v(*this);
+ UChar c = v.characterAfter();
+ // The space must not be in another paragraph and it must be editable.
+ if (!isEndOfParagraph(v) && v.next(true).isNotNull())
+ if (considerNonCollapsibleWhitespace ? (isSpaceOrNewline(c) || c == noBreakSpace) : isCollapsibleWhitespace(c))
+ return *this;
+
+ return Position();
+}
+
+void Position::debugPosition(const char* msg) const
+{
+ if (isNull())
+ fprintf(stderr, "Position [%s]: null\n", msg);
+ else
+ fprintf(stderr, "Position [%s]: %s [%p] at %d\n", msg, node()->nodeName().utf8().data(), node(), offset());
+}
+
+#ifndef NDEBUG
+
+void Position::formatForDebugger(char* buffer, unsigned length) const
+{
+ String result;
+
+ if (isNull())
+ result = "<null>";
+ else {
+ char s[1024];
+ result += "offset ";
+ result += String::number(m_offset);
+ result += " of ";
+ m_node->formatForDebugger(s, sizeof(s));
+ result += s;
+ }
+
+ strncpy(buffer, result.utf8().data(), length - 1);
+}
+
+void Position::showTreeForThis() const
+{
+ if (m_node)
+ m_node->showTreeForThis();
+}
+
+#endif
+
+Position startPosition(const Range *r)
+{
+ if (!r || r->isDetached())
+ return Position();
+ ExceptionCode ec;
+ return Position(r->startContainer(ec), r->startOffset(ec));
+}
+
+Position endPosition(const Range *r)
+{
+ if (!r || r->isDetached())
+ return Position();
+ ExceptionCode ec;
+ return Position(r->endContainer(ec), r->endOffset(ec));
+}
+
+} // namespace WebCore
+
+#ifndef NDEBUG
+
+void showTree(const WebCore::Position& pos)
+{
+ pos.showTreeForThis();
+}
+
+void showTree(const WebCore::Position* pos)
+{
+ if (pos)
+ pos->showTreeForThis();
+}
+
+#endif
diff --git a/WebCore/dom/Position.h b/WebCore/dom/Position.h
new file mode 100644
index 0000000..8b99bc2
--- /dev/null
+++ b/WebCore/dom/Position.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2004, 2006 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 Position_h
+#define Position_h
+
+#include "Node.h"
+#include "TextAffinity.h"
+
+namespace WebCore {
+
+class CSSComputedStyleDeclaration;
+class Element;
+class PositionIterator;
+class Range;
+
+enum EUsingComposedCharacters { NotUsingComposedCharacters = false, UsingComposedCharacters = true };
+
+class Position
+{
+public:
+ Position() : m_node(0), m_offset(0) { }
+ Position(Node*, int offset);
+ Position(const PositionIterator&);
+
+ void clear();
+
+ Node *node() const { return m_node.get(); }
+ Element* documentElement() const;
+ int offset() const { return m_offset; }
+
+ bool isNull() const { return m_node == 0; }
+ bool isNotNull() const { return m_node != 0; }
+
+ Element* element() const;
+ PassRefPtr<CSSComputedStyleDeclaration> computedStyle() const;
+
+ // Move up or down the DOM by one position.
+ // Offsets are computed using render text for nodes that have renderers - but note that even when
+ // using composed characters, the result may be inside a single user-visible character if a ligature is formed.
+ Position previous(EUsingComposedCharacters usingComposedCharacters=NotUsingComposedCharacters) const;
+ Position next(EUsingComposedCharacters usingComposedCharacters=NotUsingComposedCharacters) const;
+ static int uncheckedPreviousOffset(const Node*, int current);
+ static int uncheckedNextOffset(const Node*, int current);
+
+ bool atStart() const;
+ bool atEnd() const;
+
+ // FIXME: Make these non-member functions and put them somewhere in the editing directory.
+ // These aren't really basic "position" operations. More high level editing helper functions.
+ Position leadingWhitespacePosition(EAffinity, bool considerNonCollapsibleWhitespace = false) const;
+ Position trailingWhitespacePosition(EAffinity, bool considerNonCollapsibleWhitespace = false) const;
+
+ // p.upstream() through p.downstream() is the range of positions that map to the same VisiblePosition as p.
+ Position upstream() const;
+ Position downstream() const;
+
+ bool isCandidate() const;
+ bool inRenderedText() const;
+ bool isRenderedCharacter() const;
+ bool rendersInDifferentPosition(const Position &pos) const;
+
+ static bool hasRenderedNonAnonymousDescendantsWithHeight(RenderObject*);
+ static bool nodeIsUserSelectNone(Node*);
+
+ void debugPosition(const char* msg = "") const;
+
+#ifndef NDEBUG
+ void formatForDebugger(char* buffer, unsigned length) const;
+ void showTreeForThis() const;
+#endif
+
+private:
+ int renderedOffset() const;
+
+ Position previousCharacterPosition(EAffinity) const;
+ Position nextCharacterPosition(EAffinity) const;
+ RefPtr<Node> m_node;
+ int m_offset;
+};
+
+inline bool operator==(const Position &a, const Position &b)
+{
+ return a.node() == b.node() && a.offset() == b.offset();
+}
+
+inline bool operator!=(const Position &a, const Position &b)
+{
+ return !(a == b);
+}
+
+Position startPosition(const Range*);
+Position endPosition(const Range*);
+
+} // namespace WebCore
+
+#ifndef NDEBUG
+// Outside the WebCore namespace for ease of invocation from gdb.
+void showTree(const WebCore::Position&);
+void showTree(const WebCore::Position*);
+#endif
+
+#endif // Position_h
diff --git a/WebCore/dom/PositionIterator.cpp b/WebCore/dom/PositionIterator.cpp
new file mode 100644
index 0000000..110b14e
--- /dev/null
+++ b/WebCore/dom/PositionIterator.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2007 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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.
+ */
+
+#include "config.h"
+#include "PositionIterator.h"
+
+#include "Node.h"
+#include "RenderObject.h"
+#include "htmlediting.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+void PositionIterator::increment()
+{
+ if (!m_parent)
+ return;
+
+ if (m_child) {
+ m_parent = m_child;
+ m_child = m_parent->firstChild();
+ m_offset = 0;
+ return;
+ }
+
+ if (!m_parent->hasChildNodes() && m_offset < maxDeepOffset(m_parent))
+ m_offset = Position::uncheckedNextOffset(m_parent, m_offset);
+ else {
+ m_child = m_parent;
+ m_parent = m_child->parentNode();
+ m_child = m_child->nextSibling();
+ m_offset = 0;
+ }
+}
+
+void PositionIterator::decrement()
+{
+ if (!m_parent)
+ return;
+
+ if (m_child) {
+ m_parent = m_child->previousSibling();
+ if (m_parent) {
+ m_child = 0;
+ m_offset = m_parent->hasChildNodes() ? 0 : maxDeepOffset(m_parent);
+ } else {
+ m_child = m_child->parentNode();
+ m_parent = m_child->parentNode();
+ m_offset = 0;
+ }
+ return;
+ }
+
+ if (m_offset) {
+ m_offset = Position::uncheckedPreviousOffset(m_parent, m_offset);
+ } else {
+ if (m_parent->hasChildNodes()) {
+ m_parent = m_parent->lastChild();
+ if (!m_parent->hasChildNodes())
+ m_offset = maxDeepOffset(m_parent);
+ } else {
+ m_child = m_parent;
+ m_parent = m_parent->parentNode();
+ }
+ }
+}
+
+bool PositionIterator::atStart() const
+{
+ if (!m_parent)
+ return true;
+ if (m_parent->parentNode())
+ return false;
+ return !m_parent->hasChildNodes() && !m_offset || m_child && !m_child->previousSibling();
+}
+
+bool PositionIterator::atEnd() const
+{
+ if (!m_parent)
+ return true;
+ if (m_child)
+ return false;
+ return !m_parent->parentNode() && (m_parent->hasChildNodes() || m_offset >= maxDeepOffset(m_parent));
+}
+
+bool PositionIterator::atStartOfNode() const
+{
+ if (!m_parent)
+ return true;
+ if (!m_child)
+ return !m_parent->hasChildNodes() && !m_offset;
+ return !m_child->previousSibling();
+}
+
+bool PositionIterator::atEndOfNode() const
+{
+ if (!m_parent)
+ return true;
+ if (m_child)
+ return false;
+ return m_parent->hasChildNodes() || m_offset >= maxDeepOffset(m_parent);
+}
+
+bool PositionIterator::isCandidate() const
+{
+ if (!m_parent)
+ return false;
+
+ RenderObject* renderer = m_parent->renderer();
+ if (!renderer)
+ return false;
+
+ if (renderer->style()->visibility() != VISIBLE)
+ return false;
+
+ if (renderer->isBR())
+ return !m_offset && !Position::nodeIsUserSelectNone(m_parent->parent());
+
+ if (renderer->isText())
+ return Position(*this).inRenderedText() && !Position::nodeIsUserSelectNone(m_parent);
+
+ if (isTableElement(m_parent) || editingIgnoresContent(m_parent))
+ return (atStartOfNode() || atEndOfNode()) && !Position::nodeIsUserSelectNone(m_parent->parent());
+
+ if (!m_parent->hasTagName(htmlTag) && renderer->isBlockFlow() && !Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer) &&
+ (renderer->height() || m_parent->hasTagName(bodyTag)))
+ return atStartOfNode() && !Position::nodeIsUserSelectNone(m_parent);
+
+ return false;
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/PositionIterator.h b/WebCore/dom/PositionIterator.h
new file mode 100644
index 0000000..9c0038f
--- /dev/null
+++ b/WebCore/dom/PositionIterator.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2007 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 PositionIterator_h
+#define PositionIterator_h
+
+#include "Position.h"
+
+namespace WebCore {
+
+// A Position iterator with constant-time
+// increment, decrement, and several predicates on the Position it is at.
+// Conversion to/from Position is O(n) in the offset.
+class PositionIterator {
+public:
+ PositionIterator()
+ : m_parent(0)
+ , m_child(0)
+ , m_offset(0)
+ {
+ }
+
+ PositionIterator(const Position& pos)
+ : m_parent(pos.node())
+ , m_child(m_parent->childNode(pos.offset()))
+ , m_offset(m_child ? 0 : pos.offset())
+ {
+ }
+
+ void increment();
+ void decrement();
+
+ Node* node() const { return m_parent; }
+ int offsetInLeafNode() const { return m_offset; }
+
+ bool atStart() const;
+ bool atEnd() const;
+ bool atStartOfNode() const;
+ bool atEndOfNode() const;
+ bool isCandidate() const;
+
+private:
+ friend class Position;
+ Node* m_parent;
+ Node* m_child;
+ int m_offset;
+};
+
+} // namespace WebCore
+
+#endif // PositionIterator_h
diff --git a/WebCore/dom/ProcessingInstruction.cpp b/WebCore/dom/ProcessingInstruction.cpp
new file mode 100644
index 0000000..34b00d4
--- /dev/null
+++ b/WebCore/dom/ProcessingInstruction.cpp
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2000 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "ProcessingInstruction.h"
+
+#include "CSSStyleSheet.h"
+#include "CachedCSSStyleSheet.h"
+#include "CachedXSLStyleSheet.h"
+#include "Document.h"
+#include "DocLoader.h"
+#include "ExceptionCode.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "XSLStyleSheet.h"
+#include "XMLTokenizer.h" // for parseAttributes()
+
+namespace WebCore {
+
+ProcessingInstruction::ProcessingInstruction(Document* doc)
+ : ContainerNode(doc)
+ , m_cachedSheet(0)
+ , m_loading(false)
+#if ENABLE(XSLT)
+ , m_isXSL(false)
+#endif
+{
+}
+
+ProcessingInstruction::ProcessingInstruction(Document* doc, const String& target, const String& data)
+ : ContainerNode(doc)
+ , m_target(target)
+ , m_data(data)
+ , m_cachedSheet(0)
+ , m_loading(false)
+#if ENABLE(XSLT)
+ , m_isXSL(false)
+#endif
+{
+}
+
+ProcessingInstruction::~ProcessingInstruction()
+{
+ if (m_cachedSheet)
+ m_cachedSheet->deref(this);
+}
+
+void ProcessingInstruction::setData(const String& data, ExceptionCode& ec)
+{
+ // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
+ if (isReadOnlyNode()) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return;
+ }
+ m_data = data;
+}
+
+String ProcessingInstruction::nodeName() const
+{
+ return m_target;
+}
+
+Node::NodeType ProcessingInstruction::nodeType() const
+{
+ return PROCESSING_INSTRUCTION_NODE;
+}
+
+String ProcessingInstruction::nodeValue() const
+{
+ return m_data;
+}
+
+void ProcessingInstruction::setNodeValue(const String& nodeValue, ExceptionCode& ec)
+{
+ // NO_MODIFICATION_ALLOWED_ERR: taken care of by setData()
+ setData(nodeValue, ec);
+}
+
+PassRefPtr<Node> ProcessingInstruction::cloneNode(bool /*deep*/)
+{
+ // ### copy m_localHref
+ return new ProcessingInstruction(document(), m_target, m_data);
+}
+
+// DOM Section 1.1.1
+bool ProcessingInstruction::childTypeAllowed(NodeType)
+{
+ return false;
+}
+
+bool ProcessingInstruction::checkStyleSheet()
+{
+ if (m_target == "xml-stylesheet") {
+ // see http://www.w3.org/TR/xml-stylesheet/
+ // ### support stylesheet included in a fragment of this (or another) document
+ // ### make sure this gets called when adding from javascript
+ bool attrsOk;
+ const HashMap<String, String> attrs = parseAttributes(m_data, attrsOk);
+ if (!attrsOk)
+ return true;
+ HashMap<String, String>::const_iterator i = attrs.find("type");
+ String type;
+ if (i != attrs.end())
+ type = i->second;
+
+ bool isCSS = type.isEmpty() || type == "text/css";
+#if ENABLE(XSLT)
+ m_isXSL = (type == "text/xml" || type == "text/xsl" || type == "application/xml" ||
+ type == "application/xhtml+xml" || type == "application/rss+xml" || type == "application/atom=xml");
+ if (!isCSS && !m_isXSL)
+#else
+ if (!isCSS)
+#endif
+ return true;
+
+ String href = attrs.get("href");
+
+ if (href.length() > 1) {
+ if (href[0] == '#') {
+ m_localHref = href.substring(1);
+#if ENABLE(XSLT)
+ // We need to make a synthetic XSLStyleSheet that is embedded. It needs to be able
+ // to kick off import/include loads that can hang off some parent sheet.
+ if (m_isXSL) {
+ m_sheet = new XSLStyleSheet(this, m_localHref, true);
+ m_loading = false;
+ }
+ return !m_isXSL;
+#endif
+ }
+ else
+ {
+ // FIXME: some validation on the URL?
+ if (document()->frame()) {
+ m_loading = true;
+ document()->addPendingSheet();
+ if (m_cachedSheet)
+ m_cachedSheet->deref(this);
+#if ENABLE(XSLT)
+ if (m_isXSL)
+ m_cachedSheet = document()->docLoader()->requestXSLStyleSheet(document()->completeURL(href).string());
+ else
+#endif
+ {
+ String charset = attrs.get("charset");
+ if (charset.isEmpty())
+ charset = document()->frame()->loader()->encoding();
+
+ m_cachedSheet = document()->docLoader()->requestCSSStyleSheet(document()->completeURL(href).string(), charset);
+ }
+ if (m_cachedSheet)
+ m_cachedSheet->ref(this);
+#if ENABLE(XSLT)
+ return !m_isXSL;
+#endif
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+bool ProcessingInstruction::isLoading() const
+{
+ if (m_loading)
+ return true;
+ if (!m_sheet)
+ return false;
+ return m_sheet->isLoading();
+}
+
+bool ProcessingInstruction::sheetLoaded()
+{
+ if (!isLoading()) {
+ document()->removePendingSheet();
+ return true;
+ }
+ return false;
+}
+
+void ProcessingInstruction::setCSSStyleSheet(const String& url, const String& charset, const CachedCSSStyleSheet* sheet)
+{
+#if ENABLE(XSLT)
+ ASSERT(!m_isXSL);
+#endif
+ m_sheet = new CSSStyleSheet(this, url, charset);
+ parseStyleSheet(sheet->sheetText());
+}
+
+#if ENABLE(XSLT)
+void ProcessingInstruction::setXSLStyleSheet(const String& url, const String& sheet)
+{
+ ASSERT(m_isXSL);
+ m_sheet = new XSLStyleSheet(this, url);
+ parseStyleSheet(sheet);
+}
+#endif
+
+void ProcessingInstruction::parseStyleSheet(const String& sheet)
+{
+ m_sheet->parseString(sheet, true);
+ if (m_cachedSheet)
+ m_cachedSheet->deref(this);
+ m_cachedSheet = 0;
+
+ m_loading = false;
+ m_sheet->checkLoaded();
+}
+
+String ProcessingInstruction::toString() const
+{
+ String result = "<?";
+ result += m_target;
+ result += " ";
+ result += m_data;
+ result += "?>";
+ return result;
+}
+
+void ProcessingInstruction::setCSSStyleSheet(CSSStyleSheet* sheet)
+{
+ ASSERT(!m_cachedSheet);
+ ASSERT(!m_loading);
+ m_sheet = sheet;
+}
+
+bool ProcessingInstruction::offsetInCharacters() const
+{
+ return true;
+}
+
+int ProcessingInstruction::maxCharacterOffset() const
+{
+ return static_cast<int>(m_data.length());
+}
+
+} // namespace
diff --git a/WebCore/dom/ProcessingInstruction.h b/WebCore/dom/ProcessingInstruction.h
new file mode 100644
index 0000000..be4a63e
--- /dev/null
+++ b/WebCore/dom/ProcessingInstruction.h
@@ -0,0 +1,89 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2000 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef ProcessingInstruction_h
+#define ProcessingInstruction_h
+
+#include "CachedResourceClient.h"
+#include "ContainerNode.h"
+
+namespace WebCore {
+
+class StyleSheet;
+class CSSStyleSheet;
+
+class ProcessingInstruction : public ContainerNode, private CachedResourceClient
+{
+public:
+ ProcessingInstruction(Document*);
+ ProcessingInstruction(Document*, const String& target, const String& data);
+ virtual ~ProcessingInstruction();
+
+ // DOM methods & attributes for Notation
+ String target() const { return m_target; }
+ String data() const { return m_data; }
+ void setData(const String&, ExceptionCode&);
+
+ virtual String nodeName() const;
+ virtual NodeType nodeType() const;
+ virtual String nodeValue() const;
+ virtual void setNodeValue(const String&, ExceptionCode&);
+ virtual PassRefPtr<Node> cloneNode(bool deep);
+ virtual bool childTypeAllowed(NodeType);
+ virtual bool offsetInCharacters() const;
+ virtual int maxCharacterOffset() const;
+
+ // Other methods (not part of DOM)
+ String localHref() const { return m_localHref; }
+ StyleSheet* sheet() const { return m_sheet.get(); }
+ bool checkStyleSheet();
+ virtual void setCSSStyleSheet(const String& url, const String& charset, const CachedCSSStyleSheet*);
+#if ENABLE(XSLT)
+ virtual void setXSLStyleSheet(const String& url, const String& sheet);
+#endif
+ void setCSSStyleSheet(CSSStyleSheet*);
+ bool isLoading() const;
+ virtual bool sheetLoaded();
+ virtual String toString() const;
+
+#if ENABLE(XSLT)
+ bool isXSL() const { return m_isXSL; }
+#endif
+
+private:
+ void parseStyleSheet(const String& sheet);
+
+ String m_target;
+ String m_data;
+ String m_localHref;
+ CachedResource* m_cachedSheet;
+ RefPtr<StyleSheet> m_sheet;
+ bool m_loading;
+#if ENABLE(XSLT)
+ bool m_isXSL;
+#endif
+};
+
+} //namespace
+
+#endif
diff --git a/WebCore/dom/ProcessingInstruction.idl b/WebCore/dom/ProcessingInstruction.idl
new file mode 100644
index 0000000..d0923f1
--- /dev/null
+++ b/WebCore/dom/ProcessingInstruction.idl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module core {
+
+ interface [
+ GenerateConstructor,
+ InterfaceUUID=5947E8F8-B5CB-4a51-B883-B91F344F1E13,
+ ImplementationUUID=7EEC0376-3D76-4643-A964-97B8AC1FB6D3
+ ] ProcessingInstruction : Node {
+
+ // DOM Level 1
+
+ readonly attribute [ConvertNullStringTo=Null] DOMString target;
+ attribute [ConvertNullStringTo=Null, ConvertNullToNullString] DOMString data
+ setter raises(DOMException);
+
+#if !defined(LANGUAGE_COM)
+ // interface LinkStyle from DOM Level 2 Style Sheets
+ readonly attribute StyleSheet sheet;
+#endif
+
+ };
+
+}
diff --git a/WebCore/dom/ProgressEvent.cpp b/WebCore/dom/ProgressEvent.cpp
new file mode 100644
index 0000000..99de500
--- /dev/null
+++ b/WebCore/dom/ProgressEvent.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2007, 2008 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+#include "config.h"
+#include "ProgressEvent.h"
+
+namespace WebCore {
+
+ProgressEvent::ProgressEvent()
+ : m_lengthComputable(false)
+ , m_loaded(0)
+ , m_total(0)
+{
+}
+
+ProgressEvent::ProgressEvent(const AtomicString& type, bool lengthComputable, unsigned loaded, unsigned total)
+ : Event(type, false, true)
+ , m_lengthComputable(lengthComputable)
+ , m_loaded(loaded)
+ , m_total(total)
+{
+}
+
+void ProgressEvent::initProgressEvent(const AtomicString& typeArg,
+ bool canBubbleArg,
+ bool cancelableArg,
+ bool lengthComputableArg,
+ unsigned loadedArg,
+ unsigned totalArg)
+{
+ if (dispatched())
+ return;
+
+ initEvent(typeArg, canBubbleArg, cancelableArg);
+
+ m_lengthComputable = lengthComputableArg;
+ m_loaded = loadedArg;
+ m_total = totalArg;
+}
+
+}
diff --git a/WebCore/dom/ProgressEvent.h b/WebCore/dom/ProgressEvent.h
new file mode 100644
index 0000000..e215091
--- /dev/null
+++ b/WebCore/dom/ProgressEvent.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2007, 2008 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 ProgressEvent_h
+#define ProgressEvent_h
+
+#include "Event.h"
+
+namespace WebCore {
+
+ class ProgressEvent : public Event {
+ public:
+ ProgressEvent();
+ ProgressEvent(const AtomicString& type, bool lengthComputable, unsigned loaded, unsigned total);
+
+ void initProgressEvent(const AtomicString& typeArg,
+ bool canBubbleArg,
+ bool cancelableArg,
+ bool lengthComputableArg,
+ unsigned loadedArg,
+ unsigned totalArg);
+
+ bool lengthComputable() const { return m_lengthComputable; }
+ unsigned loaded() const { return m_loaded; }
+ unsigned total() const { return m_total; }
+
+ virtual bool isProgressEvent() const { return true; }
+
+ private:
+ bool m_lengthComputable;
+ unsigned m_loaded;
+ unsigned m_total;
+ };
+}
+
+#endif // ProgressEvent_h
+
diff --git a/WebCore/dom/ProgressEvent.idl b/WebCore/dom/ProgressEvent.idl
new file mode 100644
index 0000000..2db72af
--- /dev/null
+++ b/WebCore/dom/ProgressEvent.idl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2007 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+module events {
+
+ interface [
+ GenerateConstructor
+ ] ProgressEvent : Event {
+ readonly attribute boolean lengthComputable;
+ readonly attribute unsigned long loaded;
+ readonly attribute unsigned long total;
+ void initProgressEvent(in DOMString typeArg,
+ in boolean canBubbleArg,
+ in boolean cancelableArg,
+ in boolean lengthComputableArg,
+ in unsigned long loadedArg,
+ in unsigned long totalArg);
+ };
+
+}
diff --git a/WebCore/dom/QualifiedName.cpp b/WebCore/dom/QualifiedName.cpp
new file mode 100644
index 0000000..c9d7e28
--- /dev/null
+++ b/WebCore/dom/QualifiedName.cpp
@@ -0,0 +1,181 @@
+/**
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#ifdef AVOID_STATIC_CONSTRUCTORS
+#define WEBCORE_QUALIFIEDNAME_HIDE_GLOBALS 1
+#else
+#define QNAME_DEFAULT_CONSTRUCTOR
+#endif
+
+#include "QualifiedName.h"
+#include "StaticConstructors.h"
+#include <wtf/Assertions.h>
+#include <wtf/HashSet.h>
+
+namespace WebCore {
+
+struct QualifiedNameComponents {
+ StringImpl* m_prefix;
+ StringImpl* m_localName;
+ StringImpl* m_namespace;
+};
+
+// Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's
+static const unsigned PHI = 0x9e3779b9U;
+
+static inline unsigned hashComponents(const QualifiedNameComponents& buf)
+{
+ ASSERT(sizeof(QualifiedNameComponents) % (sizeof(uint16_t) * 2) == 0);
+
+ unsigned l = sizeof(QualifiedNameComponents) / (sizeof(uint16_t) * 2);
+ const uint16_t* s = reinterpret_cast<const uint16_t*>(&buf);
+ uint32_t hash = PHI;
+
+ // Main loop
+ for (; l > 0; l--) {
+ hash += s[0];
+ uint32_t tmp = (s[1] << 11) ^ hash;
+ hash = (hash << 16) ^ tmp;
+ s += 2;
+ hash += hash >> 11;
+ }
+
+ // Force "avalanching" of final 127 bits
+ hash ^= hash << 3;
+ hash += hash >> 5;
+ hash ^= hash << 2;
+ hash += hash >> 15;
+ hash ^= hash << 10;
+
+ // this avoids ever returning a hash code of 0, since that is used to
+ // signal "hash not computed yet", using a value that is likely to be
+ // effectively the same as 0 when the low bits are masked
+ if (hash == 0)
+ hash = 0x80000000;
+
+ return hash;
+}
+
+struct QNameHash {
+ static unsigned hash(const QualifiedName::QualifiedNameImpl* name) {
+ QualifiedNameComponents c = { name->m_prefix.impl(), name->m_localName.impl(), name->m_namespace.impl() };
+ return hashComponents(c);
+ }
+
+ static bool equal(const QualifiedName::QualifiedNameImpl* a, const QualifiedName::QualifiedNameImpl* b) { return a == b; }
+
+ static const bool safeToCompareToEmptyOrDeleted = false;
+};
+
+typedef HashSet<QualifiedName::QualifiedNameImpl*, QNameHash> QNameSet;
+
+struct QNameComponentsTranslator {
+ static unsigned hash(const QualifiedNameComponents& components) {
+ return hashComponents(components);
+ }
+ static bool equal(QualifiedName::QualifiedNameImpl* name, const QualifiedNameComponents& c) {
+ return c.m_prefix == name->m_prefix.impl() && c.m_localName == name->m_localName.impl() && c.m_namespace == name->m_namespace.impl();
+ }
+ static void translate(QualifiedName::QualifiedNameImpl*& location, const QualifiedNameComponents& components, unsigned hash) {
+ location = QualifiedName::QualifiedNameImpl::create(components.m_prefix, components.m_localName, components.m_namespace).releaseRef();
+ }
+};
+
+static QNameSet* gNameCache;
+
+QualifiedName::QualifiedName(const AtomicString& p, const AtomicString& l, const AtomicString& n)
+ : m_impl(0)
+{
+ if (!gNameCache)
+ gNameCache = new QNameSet;
+ QualifiedNameComponents components = { p.impl(), l.impl(), n.impl() };
+ pair<QNameSet::iterator, bool> addResult = gNameCache->add<QualifiedNameComponents, QNameComponentsTranslator>(components);
+ m_impl = *addResult.first;
+ if (!addResult.second)
+ m_impl->ref();
+}
+
+QualifiedName::~QualifiedName()
+{
+ deref();
+}
+
+QualifiedName::QualifiedName(const QualifiedName& other)
+{
+ m_impl = other.m_impl;
+ ref();
+}
+
+const QualifiedName& QualifiedName::operator=(const QualifiedName& other)
+{
+ if (m_impl != other.m_impl) {
+ deref();
+ m_impl = other.m_impl;
+ ref();
+ }
+
+ return *this;
+}
+
+void QualifiedName::deref()
+{
+#ifdef QNAME_DEFAULT_CONSTRUCTOR
+ if (!m_impl)
+ return;
+#endif
+
+ if (m_impl->hasOneRef())
+ gNameCache->remove(m_impl);
+ m_impl->deref();
+}
+
+void QualifiedName::setPrefix(const AtomicString& prefix)
+{
+ QualifiedName other(prefix, localName(), namespaceURI());
+ *this = other;
+}
+
+String QualifiedName::toString() const
+{
+ String local = localName();
+ if (hasPrefix())
+ return prefix() + ":" + local;
+ return local;
+}
+
+// Global init routines
+DEFINE_GLOBAL(QualifiedName, anyName, nullAtom, starAtom, starAtom)
+
+void QualifiedName::init()
+{
+ static bool initialized;
+ if (!initialized) {
+ // Use placement new to initialize the globals.
+
+ AtomicString::init();
+ new ((void*)&anyName) QualifiedName(nullAtom, starAtom, starAtom);
+ initialized = true;
+ }
+}
+
+}
diff --git a/WebCore/dom/QualifiedName.h b/WebCore/dom/QualifiedName.h
new file mode 100644
index 0000000..5aa8abf
--- /dev/null
+++ b/WebCore/dom/QualifiedName.h
@@ -0,0 +1,97 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2005 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+#ifndef QualifiedName_h
+#define QualifiedName_h
+
+#include "AtomicString.h"
+
+namespace WebCore {
+
+class QualifiedName {
+public:
+ class QualifiedNameImpl : public RefCounted<QualifiedNameImpl> {
+ public:
+ static PassRefPtr<QualifiedNameImpl> create(const AtomicString& p, const AtomicString& l, const AtomicString& n)
+ {
+ return adoptRef(new QualifiedNameImpl(p, l, n));
+ }
+
+ AtomicString m_prefix;
+ AtomicString m_localName;
+ AtomicString m_namespace;
+
+ private:
+ QualifiedNameImpl(const AtomicString& p, const AtomicString& l, const AtomicString& n)
+ : m_prefix(p)
+ , m_localName(l)
+ , m_namespace(n)
+ {
+ }
+ };
+
+ QualifiedName(const AtomicString& prefix, const AtomicString& localName, const AtomicString& namespaceURI);
+ ~QualifiedName();
+#ifdef QNAME_DEFAULT_CONSTRUCTOR
+ QualifiedName() : m_impl(0) { }
+#endif
+
+ QualifiedName(const QualifiedName&);
+ const QualifiedName& operator=(const QualifiedName&);
+
+ bool operator==(const QualifiedName& other) const { return m_impl == other.m_impl; }
+ bool operator!=(const QualifiedName& other) const { return !(*this == other); }
+
+ bool matches(const QualifiedName& other) const { return m_impl == other.m_impl || (localName() == other.localName() && namespaceURI() == other.namespaceURI()); }
+
+ bool hasPrefix() const { return m_impl->m_prefix != nullAtom; }
+ void setPrefix(const AtomicString& prefix);
+
+ const AtomicString& prefix() const { return m_impl->m_prefix; }
+ const AtomicString& localName() const { return m_impl->m_localName; }
+ const AtomicString& namespaceURI() const { return m_impl->m_namespace; }
+
+ String toString() const;
+
+ QualifiedNameImpl* impl() const { return m_impl; }
+
+ // Init routine for globals
+ static void init();
+
+private:
+ void ref() { m_impl->ref(); }
+ void deref();
+
+ QualifiedNameImpl* m_impl;
+};
+
+#ifndef WEBCORE_QUALIFIEDNAME_HIDE_GLOBALS
+extern const QualifiedName anyName;
+inline const QualifiedName& anyQName() { return anyName; }
+#endif
+
+inline bool operator==(const AtomicString& a, const QualifiedName& q) { return a == q.localName(); }
+inline bool operator!=(const AtomicString& a, const QualifiedName& q) { return a != q.localName(); }
+inline bool operator==(const QualifiedName& q, const AtomicString& a) { return a == q.localName(); }
+inline bool operator!=(const QualifiedName& q, const AtomicString& a) { return a != q.localName(); }
+
+}
+#endif
diff --git a/WebCore/dom/Range.cpp b/WebCore/dom/Range.cpp
new file mode 100644
index 0000000..88292c3
--- /dev/null
+++ b/WebCore/dom/Range.cpp
@@ -0,0 +1,1718 @@
+/**
+ * (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Gunnstein Lye (gunnstein@netcom.no)
+ * (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
+ * (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "Range.h"
+
+#include "CString.h"
+#include "Document.h"
+#include "DocumentFragment.h"
+#include "ExceptionCode.h"
+#include "HTMLElement.h"
+#include "HTMLNames.h"
+#include "ProcessingInstruction.h"
+#include "RangeException.h"
+#include "RenderBlock.h"
+#include "Text.h"
+#include "TextIterator.h"
+#include "markup.h"
+#include "visible_units.h"
+#include <stdio.h>
+
+namespace WebCore {
+
+using namespace std;
+using namespace HTMLNames;
+
+#ifndef NDEBUG
+class RangeCounter {
+public:
+ static unsigned count;
+ ~RangeCounter()
+ {
+ if (count)
+ fprintf(stderr, "LEAK: %u Range\n", count);
+ }
+};
+unsigned RangeCounter::count = 0;
+static RangeCounter rangeCounter;
+#endif
+
+Range::Range(Document* ownerDocument)
+ : RefCounted<Range>(0)
+ , m_ownerDocument(ownerDocument)
+ , m_startContainer(ownerDocument)
+ , m_startOffset(0)
+ , m_endContainer(ownerDocument)
+ , m_endOffset(0)
+ , m_detached(false)
+{
+#ifndef NDEBUG
+ ++RangeCounter::count;
+#endif
+}
+
+Range::Range(Document* ownerDocument,
+ Node* startContainer, int startOffset,
+ Node* endContainer, int endOffset)
+ : RefCounted<Range>(0)
+ , m_ownerDocument(ownerDocument)
+ , m_startContainer(ownerDocument)
+ , m_startOffset(0)
+ , m_endContainer(ownerDocument)
+ , m_endOffset(0)
+ , m_detached(false)
+{
+#ifndef NDEBUG
+ ++RangeCounter::count;
+#endif
+ // Simply setting the containers and offsets directly would not do any of the checking
+ // that setStart and setEnd do, so we must call those functions.
+ ExceptionCode ec = 0;
+ setStart(startContainer, startOffset, ec);
+ ASSERT(ec == 0);
+ setEnd(endContainer, endOffset, ec);
+ ASSERT(ec == 0);
+}
+
+Range::Range(Document* ownerDocument, const Position& start, const Position& end)
+ : RefCounted<Range>(0)
+ , m_ownerDocument(ownerDocument)
+ , m_startContainer(ownerDocument)
+ , m_startOffset(0)
+ , m_endContainer(ownerDocument)
+ , m_endOffset(0)
+ , m_detached(false)
+{
+#ifndef NDEBUG
+ ++RangeCounter::count;
+#endif
+ // Simply setting the containers and offsets directly would not do any of the checking
+ // that setStart and setEnd do, so we must call those functions.
+ ExceptionCode ec = 0;
+ setStart(start.node(), start.offset(), ec);
+ ASSERT(ec == 0);
+ setEnd(end.node(), end.offset(), ec);
+ ASSERT(ec == 0);
+}
+
+Range::~Range()
+{
+#ifndef NDEBUG
+ --RangeCounter::count;
+#endif
+}
+
+Node *Range::startContainer(ExceptionCode& ec) const
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return 0;
+ }
+
+ return m_startContainer.get();
+}
+
+int Range::startOffset(ExceptionCode& ec) const
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return 0;
+ }
+
+ return m_startOffset;
+}
+
+Node *Range::endContainer(ExceptionCode& ec) const
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return 0;
+ }
+
+ return m_endContainer.get();
+}
+
+int Range::endOffset(ExceptionCode& ec) const
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return 0;
+ }
+
+ return m_endOffset;
+}
+
+Node *Range::commonAncestorContainer(ExceptionCode& ec) const
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return 0;
+ }
+
+ Node *com = commonAncestorContainer(m_startContainer.get(), m_endContainer.get());
+ if (!com) // should never happen
+ ec = WRONG_DOCUMENT_ERR;
+ return com;
+}
+
+Node *Range::commonAncestorContainer(Node *containerA, Node *containerB)
+{
+ Node *parentStart;
+
+ for (parentStart = containerA; parentStart; parentStart = parentStart->parentNode()) {
+ Node *parentEnd = containerB;
+ while (parentEnd && (parentStart != parentEnd))
+ parentEnd = parentEnd->parentNode();
+ if (parentStart == parentEnd)
+ break;
+ }
+
+ return parentStart;
+}
+
+bool Range::collapsed(ExceptionCode& ec) const
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return 0;
+ }
+
+ return (m_startContainer == m_endContainer && m_startOffset == m_endOffset);
+}
+
+void Range::setStart( Node *refNode, int offset, ExceptionCode& ec)
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return;
+ }
+
+ if (!refNode) {
+ ec = NOT_FOUND_ERR;
+ return;
+ }
+
+ if (refNode->document() != m_ownerDocument) {
+ ec = WRONG_DOCUMENT_ERR;
+ return;
+ }
+
+ ec = 0;
+ checkNodeWOffset(refNode, offset, ec);
+ if (ec)
+ return;
+
+ m_startContainer = refNode;
+ m_startOffset = offset;
+
+ // check if different root container
+ Node* endRootContainer = m_endContainer.get();
+ while (endRootContainer->parentNode())
+ endRootContainer = endRootContainer->parentNode();
+ Node* startRootContainer = m_startContainer.get();
+ while (startRootContainer->parentNode())
+ startRootContainer = startRootContainer->parentNode();
+ if (startRootContainer != endRootContainer)
+ collapse(true, ec);
+ // check if new start after end
+ else if (compareBoundaryPoints(m_startContainer.get(), m_startOffset, m_endContainer.get(), m_endOffset) > 0)
+ collapse(true, ec);
+}
+
+void Range::setEnd( Node *refNode, int offset, ExceptionCode& ec)
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return;
+ }
+
+ if (!refNode) {
+ ec = NOT_FOUND_ERR;
+ return;
+ }
+
+ if (refNode->document() != m_ownerDocument) {
+ ec = WRONG_DOCUMENT_ERR;
+ return;
+ }
+
+ ec = 0;
+ checkNodeWOffset(refNode, offset, ec);
+ if (ec)
+ return;
+
+ m_endContainer = refNode;
+ m_endOffset = offset;
+
+ // check if different root container
+ Node* endRootContainer = m_endContainer.get();
+ while (endRootContainer->parentNode())
+ endRootContainer = endRootContainer->parentNode();
+ Node* startRootContainer = m_startContainer.get();
+ while (startRootContainer->parentNode())
+ startRootContainer = startRootContainer->parentNode();
+ if (startRootContainer != endRootContainer)
+ collapse(false, ec);
+ // check if new end before start
+ if (compareBoundaryPoints(m_startContainer.get(), m_startOffset, m_endContainer.get(), m_endOffset) > 0)
+ collapse(false, ec);
+}
+
+void Range::collapse( bool toStart, ExceptionCode& ec)
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return;
+ }
+
+ if (toStart) { // collapse to start
+ m_endContainer = m_startContainer;
+ m_endOffset = m_startOffset;
+ } else { // collapse to end
+ m_startContainer = m_endContainer;
+ m_startOffset = m_endOffset;
+ }
+}
+
+bool Range::isPointInRange(Node* refNode, int offset, ExceptionCode& ec)
+{
+ if (!refNode) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+
+ if (m_detached && refNode->attached()) {
+ ec = INVALID_STATE_ERR;
+ return false;
+ }
+
+ if (!m_detached && !refNode->attached()) {
+ // firefox doesn't throw an exception for this case; it returns false
+ return false;
+ }
+
+ if (refNode->document() != m_ownerDocument) {
+ ec = WRONG_DOCUMENT_ERR;
+ return false;
+ }
+
+ ec = 0;
+ checkNodeWOffset(refNode, offset, ec);
+ if (ec)
+ return false;
+
+ // point is not before the start and not after the end
+ if ((compareBoundaryPoints(refNode, offset, m_startContainer.get(), m_startOffset) != -1) &&
+ (compareBoundaryPoints(refNode, offset, m_endContainer.get(), m_endOffset) != 1))
+ return true;
+ else
+ return false;
+}
+
+short Range::comparePoint(Node* refNode, int offset, ExceptionCode& ec)
+{
+ // http://developer.mozilla.org/en/docs/DOM:range.comparePoint
+ // This method returns -1, 0 or 1 depending on if the point described by the
+ // refNode node and an offset within the node is before, same as, or after the range respectively.
+
+ if (!refNode) {
+ ec = NOT_FOUND_ERR;
+ return 0;
+ }
+
+ if (m_detached && refNode->attached()) {
+ ec = INVALID_STATE_ERR;
+ return 0;
+ }
+
+ if (!m_detached && !refNode->attached()) {
+ // firefox doesn't throw an exception for this case; it returns -1
+ return -1;
+ }
+
+ if (refNode->document() != m_ownerDocument) {
+ ec = WRONG_DOCUMENT_ERR;
+ return 0;
+ }
+
+ ec = 0;
+ checkNodeWOffset(refNode, offset, ec);
+ if (ec)
+ return 0;
+
+ // compare to start, and point comes before
+ if (compareBoundaryPoints(refNode, offset, m_startContainer.get(), m_startOffset) == -1)
+ return -1;
+
+ // compare to end, and point comes after
+ if (compareBoundaryPoints(refNode, offset, m_endContainer.get(), m_endOffset) == 1)
+ return 1;
+
+ // point is in the middle of this range, or on the boundary points
+ return 0;
+}
+
+Range::CompareResults Range::compareNode(Node* refNode, ExceptionCode& ec)
+{
+ // http://developer.mozilla.org/en/docs/DOM:range.compareNode
+ // This method returns 0, 1, 2, or 3 based on if the node is before, after,
+ // before and after(surrounds), or inside the range, respectively
+
+ if (!refNode) {
+ ec = NOT_FOUND_ERR;
+ return NODE_BEFORE;
+ }
+
+ if (m_detached && refNode->attached()) {
+ ec = INVALID_STATE_ERR;
+ return NODE_BEFORE;
+ }
+
+ if (!m_detached && !refNode->attached()) {
+ // firefox doesn't throw an exception for this case; it returns 0
+ return NODE_BEFORE;
+ }
+
+ if (refNode->document() != m_ownerDocument) {
+ // firefox doesn't throw an exception for this case; it returns 0
+ return NODE_BEFORE;
+ }
+
+ Node* parentNode = refNode->parentNode();
+ unsigned nodeIndex = refNode->nodeIndex();
+
+ if (!parentNode) {
+ // if the node is the top document we should return NODE_BEFORE_AND_AFTER
+ // but we throw to match firefox behavior
+ ec = NOT_FOUND_ERR;
+ return NODE_BEFORE;
+ }
+
+ if (comparePoint(parentNode, nodeIndex, ec) == -1) { // starts before
+ if (comparePoint(parentNode, nodeIndex + 1, ec) == 1) // ends after the range
+ return NODE_BEFORE_AND_AFTER;
+ return NODE_BEFORE; // ends before or in the range
+ } else { // starts at or after the range start
+ if (comparePoint(parentNode, nodeIndex + 1, ec) == 1) // ends after the range
+ return NODE_AFTER;
+ return NODE_INSIDE; // ends inside the range
+ }
+}
+
+
+short Range::compareBoundaryPoints(CompareHow how, const Range *sourceRange, ExceptionCode& ec) const
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return 0;
+ }
+
+ if (!sourceRange) {
+ ec = NOT_FOUND_ERR;
+ return 0;
+ }
+
+ ec = 0;
+ Node *thisCont = commonAncestorContainer(ec);
+ if (ec)
+ return 0;
+ Node *sourceCont = sourceRange->commonAncestorContainer(ec);
+ if (ec)
+ return 0;
+
+ if (thisCont->document() != sourceCont->document()) {
+ ec = WRONG_DOCUMENT_ERR;
+ return 0;
+ }
+
+ Node *thisTop = thisCont;
+ Node *sourceTop = sourceCont;
+ while (thisTop->parentNode())
+ thisTop = thisTop->parentNode();
+ while (sourceTop->parentNode())
+ sourceTop = sourceTop->parentNode();
+ if (thisTop != sourceTop) { // in different DocumentFragments
+ ec = WRONG_DOCUMENT_ERR;
+ return 0;
+ }
+
+ switch(how)
+ {
+ case START_TO_START:
+ return compareBoundaryPoints( m_startContainer.get(), m_startOffset,
+ sourceRange->startContainer(ec), sourceRange->startOffset(ec) );
+ break;
+ case START_TO_END:
+ return compareBoundaryPoints( m_startContainer.get(), m_startOffset,
+ sourceRange->endContainer(ec), sourceRange->endOffset(ec) );
+ break;
+ case END_TO_END:
+ return compareBoundaryPoints( m_endContainer.get(), m_endOffset,
+ sourceRange->endContainer(ec), sourceRange->endOffset(ec) );
+ break;
+ case END_TO_START:
+ return compareBoundaryPoints( m_endContainer.get(), m_endOffset,
+ sourceRange->startContainer(ec), sourceRange->startOffset(ec) );
+ break;
+ default:
+ ec = SYNTAX_ERR;
+ return 0;
+ }
+}
+
+short Range::compareBoundaryPoints( Node *containerA, int offsetA, Node *containerB, int offsetB )
+{
+ ASSERT(containerA && containerB);
+ if (!containerA)
+ return -1;
+ if (!containerB)
+ return 1;
+ // see DOM2 traversal & range section 2.5
+
+ // case 1: both points have the same container
+ if(containerA == containerB) {
+ if (offsetA == offsetB)
+ return 0; // A is equal to B
+ if (offsetA < offsetB)
+ return -1; // A is before B
+ else
+ return 1; // A is after B
+ }
+
+ // case 2: node C (container B or an ancestor) is a child node of A
+ Node *c = containerB;
+ while (c && c->parentNode() != containerA)
+ c = c->parentNode();
+ if (c) {
+ int offsetC = 0;
+ Node *n = containerA->firstChild();
+ while (n != c && offsetC < offsetA) {
+ offsetC++;
+ n = n->nextSibling();
+ }
+
+ if (offsetA <= offsetC)
+ return -1; // A is before B
+ else
+ return 1; // A is after B
+ }
+
+ // case 3: node C (container A or an ancestor) is a child node of B
+ c = containerA;
+ while (c && c->parentNode() != containerB)
+ c = c->parentNode();
+ if (c) {
+ int offsetC = 0;
+ Node *n = containerB->firstChild();
+ while (n != c && offsetC < offsetB) {
+ offsetC++;
+ n = n->nextSibling();
+ }
+
+ if(offsetC < offsetB)
+ return -1; // A is before B
+ else
+ return 1; // A is after B
+ }
+
+ // case 4: containers A & B are siblings, or children of siblings
+ // ### we need to do a traversal here instead
+ Node *cmnRoot = commonAncestorContainer(containerA,containerB);
+ if (!cmnRoot)
+ return 0;
+ Node *childA = containerA;
+ while (childA && childA->parentNode() != cmnRoot)
+ childA = childA->parentNode();
+ if (!childA)
+ childA = cmnRoot;
+ Node *childB = containerB;
+ while (childB && childB->parentNode() != cmnRoot)
+ childB = childB->parentNode();
+ if (!childB)
+ childB = cmnRoot;
+
+ if (childA == childB)
+ return 0; // A is equal to B
+
+ Node *n = cmnRoot->firstChild();
+ while (n) {
+ if (n == childA)
+ return -1; // A is before B
+ if (n == childB)
+ return 1; // A is after B
+ n = n->nextSibling();
+ }
+
+ // Should never reach this point.
+ ASSERT(0);
+ return 0;
+}
+
+short Range::compareBoundaryPoints( const Position &a, const Position &b )
+{
+ return compareBoundaryPoints(a.node(), a.offset(), b.node(), b.offset());
+}
+
+bool Range::boundaryPointsValid() const
+{
+ return m_startContainer && m_endContainer && compareBoundaryPoints(m_startContainer.get(), m_startOffset, m_endContainer.get(), m_endOffset) <= 0;
+}
+
+void Range::deleteContents(ExceptionCode& ec) {
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return;
+ }
+
+ ec = 0;
+ checkDeleteExtract(ec);
+ if (ec)
+ return;
+
+ processContents(DELETE_CONTENTS,ec);
+}
+
+bool Range::intersectsNode(Node* refNode, ExceptionCode& ec)
+{
+ // http://developer.mozilla.org/en/docs/DOM:range.intersectsNode
+ // Returns a bool if the node intersects the range.
+
+ if (!refNode) {
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+
+ if (m_detached && refNode->attached() ||
+ !m_detached && !refNode->attached() ||
+ refNode->document() != m_ownerDocument)
+ // firefox doesn't throw an exception for these case; it returns false
+ return false;
+
+ Node* parentNode = refNode->parentNode();
+ unsigned nodeIndex = refNode->nodeIndex();
+
+ if (!parentNode) {
+ // if the node is the top document we should return NODE_BEFORE_AND_AFTER
+ // but we throw to match firefox behavior
+ ec = NOT_FOUND_ERR;
+ return false;
+ }
+
+ if (comparePoint(parentNode, nodeIndex, ec) == -1 && // starts before start
+ comparePoint(parentNode, nodeIndex + 1, ec) == -1) { // ends before start
+ return false;
+ } else if(comparePoint(parentNode, nodeIndex, ec) == 1 && // starts after end
+ comparePoint(parentNode, nodeIndex + 1, ec) == 1) { // ends after end
+ return false;
+ }
+
+ return true; //all other cases
+}
+
+PassRefPtr<DocumentFragment> Range::processContents ( ActionType action, ExceptionCode& ec)
+{
+ // ### when mutation events are implemented, we will have to take into account
+ // situations where the tree is being transformed while we delete - ugh!
+
+ // ### perhaps disable node deletion notification for this range while we do this?
+
+ RefPtr<DocumentFragment> fragment;
+ if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS)
+ fragment = new DocumentFragment(m_ownerDocument.get());
+
+ ec = 0;
+ if (collapsed(ec))
+ return fragment.release();
+ if (ec)
+ return 0;
+
+ Node *cmnRoot = commonAncestorContainer(ec);
+ if (ec)
+ return 0;
+
+ // what is the highest node that partially selects the start of the range?
+ Node *partialStart = 0;
+ if (m_startContainer != cmnRoot) {
+ partialStart = m_startContainer.get();
+ while (partialStart->parentNode() != cmnRoot)
+ partialStart = partialStart->parentNode();
+ }
+
+ // what is the highest node that partially selects the end of the range?
+ Node *partialEnd = 0;
+ if (m_endContainer != cmnRoot) {
+ partialEnd = m_endContainer.get();
+ while (partialEnd->parentNode() != cmnRoot)
+ partialEnd = partialEnd->parentNode();
+ }
+
+ // Simple case: the start and end containers are the same. We just grab
+ // everything >= start offset and < end offset
+ if (m_startContainer == m_endContainer) {
+ if(m_startContainer->nodeType() == Node::TEXT_NODE ||
+ m_startContainer->nodeType() == Node::CDATA_SECTION_NODE ||
+ m_startContainer->nodeType() == Node::COMMENT_NODE) {
+
+ if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
+ RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(m_startContainer->cloneNode(true));
+ c->deleteData(m_endOffset, c->length() - m_endOffset, ec);
+ c->deleteData(0, m_startOffset, ec);
+ fragment->appendChild(c.release(), ec);
+ }
+ if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
+ static_cast<CharacterData*>(m_startContainer.get())->deleteData(m_startOffset,m_endOffset-m_startOffset,ec);
+ m_startContainer->document()->updateLayout();
+ }
+ }
+ else if (m_startContainer->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) {
+ if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
+ RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(m_startContainer->cloneNode(true));
+ c->setData(c->data().substring(m_startOffset, m_endOffset - m_startOffset), ec);
+ fragment->appendChild(c.release(), ec);
+ }
+ if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
+ ProcessingInstruction* pi= static_cast<ProcessingInstruction*>(m_startContainer.get());
+ String data(pi->data());
+ data.remove(m_startOffset, m_endOffset - m_startOffset);
+ pi->setData(data, ec);
+ }
+ }
+ else {
+ Node *n = m_startContainer->firstChild();
+ unsigned i;
+ for (i = 0; n && i < m_startOffset; i++) // skip until m_startOffset
+ n = n->nextSibling();
+ while (n && i < m_endOffset) { // delete until m_endOffset
+ Node *next = n->nextSibling();
+ if (action == EXTRACT_CONTENTS)
+ fragment->appendChild(n,ec); // will remove n from it's parent
+ else if (action == CLONE_CONTENTS)
+ fragment->appendChild(n->cloneNode(true),ec);
+ else
+ m_startContainer->removeChild(n,ec);
+ n = next;
+ i++;
+ }
+ }
+ if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS)
+ collapse(true,ec);
+ return fragment.release();
+ }
+
+ // Complex case: Start and end containers are different.
+ // There are three possiblities here:
+ // 1. Start container == cmnRoot (End container must be a descendant)
+ // 2. End container == cmnRoot (Start container must be a descendant)
+ // 3. Neither is cmnRoot, they are both descendants
+ //
+ // In case 3, we grab everything after the start (up until a direct child
+ // of cmnRoot) into leftContents, and everything before the end (up until
+ // a direct child of cmnRoot) into rightContents. Then we process all
+ // cmnRoot children between leftContents and rightContents
+ //
+ // In case 1 or 2, we skip either processing of leftContents or rightContents,
+ // in which case the last lot of nodes either goes from the first or last
+ // child of cmnRoot.
+ //
+ // These are deleted, cloned, or extracted (i.e. both) depending on action.
+
+ RefPtr<Node> leftContents;
+ if (m_startContainer != cmnRoot) {
+ // process the left-hand side of the range, up until the last ancestor of
+ // m_startContainer before cmnRoot
+ if(m_startContainer->nodeType() == Node::TEXT_NODE ||
+ m_startContainer->nodeType() == Node::CDATA_SECTION_NODE ||
+ m_startContainer->nodeType() == Node::COMMENT_NODE) {
+
+ if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
+ RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(m_startContainer->cloneNode(true));
+ c->deleteData(0, m_startOffset, ec);
+ leftContents = c.release();
+ }
+ if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
+ static_cast<CharacterData*>(m_startContainer.get())->deleteData(
+ m_startOffset, static_cast<CharacterData*>(m_startContainer.get())->length() - m_startOffset, ec);
+ m_startContainer->document()->updateLayout();
+ }
+ }
+ else if (m_startContainer->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) {
+ if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
+ RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(m_startContainer->cloneNode(true));
+ c->setData(c->data().substring(m_startOffset), ec);
+ leftContents = c.release();
+ }
+ if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
+ ProcessingInstruction* pi= static_cast<ProcessingInstruction*>(m_startContainer.get());
+ String data(pi->data());
+ pi->setData(data.left(m_startOffset), ec);
+ }
+ }
+ else {
+ if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS)
+ leftContents = m_startContainer->cloneNode(false);
+ Node *n = m_startContainer->firstChild();
+ for (unsigned i = 0; n && i < m_startOffset; i++) // skip until m_startOffset
+ n = n->nextSibling();
+ while (n) { // process until end
+ Node *next = n->nextSibling();
+ if (action == EXTRACT_CONTENTS)
+ leftContents->appendChild(n,ec); // will remove n from m_startContainer
+ else if (action == CLONE_CONTENTS)
+ leftContents->appendChild(n->cloneNode(true),ec);
+ else
+ m_startContainer->removeChild(n,ec);
+ n = next;
+ }
+ }
+
+ Node *leftParent = m_startContainer->parentNode();
+ Node *n = m_startContainer->nextSibling();
+ for (; leftParent != cmnRoot; leftParent = leftParent->parentNode()) {
+ if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
+ RefPtr<Node> leftContentsParent = leftParent->cloneNode(false);
+ leftContentsParent->appendChild(leftContents,ec);
+ leftContents = leftContentsParent;
+ }
+
+ Node *next;
+ for (; n; n = next) {
+ next = n->nextSibling();
+ if (action == EXTRACT_CONTENTS)
+ leftContents->appendChild(n,ec); // will remove n from leftParent
+ else if (action == CLONE_CONTENTS)
+ leftContents->appendChild(n->cloneNode(true),ec);
+ else
+ leftParent->removeChild(n,ec);
+ }
+ n = leftParent->nextSibling();
+ }
+ }
+
+ RefPtr<Node> rightContents = 0;
+ if (m_endContainer != cmnRoot) {
+ // delete the right-hand side of the range, up until the last ancestor of
+ // m_endContainer before cmnRoot
+ if(m_endContainer->nodeType() == Node::TEXT_NODE ||
+ m_endContainer->nodeType() == Node::CDATA_SECTION_NODE ||
+ m_endContainer->nodeType() == Node::COMMENT_NODE) {
+
+ if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
+ RefPtr<CharacterData> c = static_pointer_cast<CharacterData>(m_endContainer->cloneNode(true));
+ c->deleteData(m_endOffset, static_cast<CharacterData*>(m_endContainer.get())->length() - m_endOffset, ec);
+ rightContents = c;
+ }
+ if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
+ static_cast<CharacterData*>(m_endContainer.get())->deleteData(0, m_endOffset, ec);
+ m_startContainer->document()->updateLayout();
+ }
+ }
+ else if (m_endContainer->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) {
+ if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
+ RefPtr<ProcessingInstruction> c = static_pointer_cast<ProcessingInstruction>(m_endContainer->cloneNode(true));
+ c->setData(c->data().left(m_endOffset), ec);
+ rightContents = c.release();
+ }
+ if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
+ ProcessingInstruction* pi= static_cast<ProcessingInstruction*>(m_endContainer.get());
+ pi->setData(pi->data().substring(m_endOffset), ec);
+ }
+ }
+ else {
+ if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS)
+ rightContents = m_endContainer->cloneNode(false);
+ Node *n = m_endContainer->firstChild();
+ if (n && m_endOffset) {
+ for (unsigned i = 0; i+1 < m_endOffset; i++) { // skip to m_endOffset
+ Node *next = n->nextSibling();
+ if (!next)
+ break;
+ n = next;
+ }
+ Node *prev;
+ for (; n; n = prev) {
+ prev = n->previousSibling();
+ if (action == EXTRACT_CONTENTS)
+ rightContents->insertBefore(n,rightContents->firstChild(),ec); // will remove n from it's parent
+ else if (action == CLONE_CONTENTS)
+ rightContents->insertBefore(n->cloneNode(true),rightContents->firstChild(),ec);
+ else
+ m_endContainer->removeChild(n,ec);
+ }
+ }
+ }
+
+ Node *rightParent = m_endContainer->parentNode();
+ Node *n = m_endContainer->previousSibling();
+ for (; rightParent != cmnRoot; rightParent = rightParent->parentNode()) {
+ if (action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) {
+ RefPtr<Node> rightContentsParent = rightParent->cloneNode(false);
+ rightContentsParent->appendChild(rightContents,ec);
+ rightContents = rightContentsParent;
+ }
+
+ Node *prev;
+ for (; n; n = prev) {
+ prev = n->previousSibling();
+ if (action == EXTRACT_CONTENTS)
+ rightContents->insertBefore(n,rightContents->firstChild(),ec); // will remove n from it's parent
+ else if (action == CLONE_CONTENTS)
+ rightContents->insertBefore(n->cloneNode(true),rightContents->firstChild(),ec);
+ else
+ rightParent->removeChild(n,ec);
+ }
+ n = rightParent->previousSibling();
+ }
+ }
+
+ // delete all children of cmnRoot between the start and end container
+
+ Node *processStart; // child of cmnRooot
+ if (m_startContainer == cmnRoot) {
+ unsigned i;
+ processStart = m_startContainer->firstChild();
+ for (i = 0; i < m_startOffset; i++)
+ processStart = processStart->nextSibling();
+ }
+ else {
+ processStart = m_startContainer.get();
+ while (processStart->parentNode() != cmnRoot)
+ processStart = processStart->parentNode();
+ processStart = processStart->nextSibling();
+ }
+ Node *processEnd; // child of cmnRooot
+ if (m_endContainer == cmnRoot) {
+ unsigned i;
+ processEnd = m_endContainer->firstChild();
+ for (i = 0; i < m_endOffset; i++)
+ processEnd = processEnd->nextSibling();
+ }
+ else {
+ processEnd = m_endContainer.get();
+ while (processEnd->parentNode() != cmnRoot)
+ processEnd = processEnd->parentNode();
+ }
+
+ // Now add leftContents, stuff in between, and rightContents to the fragment
+ // (or just delete the stuff in between)
+
+ if ((action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) && leftContents)
+ fragment->appendChild(leftContents,ec);
+
+ Node *next;
+ Node *n;
+ if (processStart) {
+ for (n = processStart; n && n != processEnd; n = next) {
+ next = n->nextSibling();
+
+ if (action == EXTRACT_CONTENTS)
+ fragment->appendChild(n,ec); // will remove from cmnRoot
+ else if (action == CLONE_CONTENTS)
+ fragment->appendChild(n->cloneNode(true),ec);
+ else
+ cmnRoot->removeChild(n,ec);
+ }
+ }
+
+ if ((action == EXTRACT_CONTENTS || action == CLONE_CONTENTS) && rightContents)
+ fragment->appendChild(rightContents,ec);
+
+ // collapse to the proper position - see spec section 2.6
+ if (action == EXTRACT_CONTENTS || action == DELETE_CONTENTS) {
+ if (!partialStart && !partialEnd)
+ collapse(true,ec);
+ else if (partialStart) {
+ m_startContainer = partialStart->parentNode();
+ m_endContainer = partialStart->parentNode();
+ m_startOffset = m_endOffset = partialStart->nodeIndex()+1;
+ }
+ else if (partialEnd) {
+ m_startContainer = partialEnd->parentNode();
+ m_endContainer = partialEnd->parentNode();
+ m_startOffset = m_endOffset = partialEnd->nodeIndex();
+ }
+ }
+ return fragment.release();
+}
+
+
+PassRefPtr<DocumentFragment> Range::extractContents(ExceptionCode& ec)
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return 0;
+ }
+
+ ec = 0;
+ checkDeleteExtract(ec);
+ if (ec)
+ return 0;
+
+ return processContents(EXTRACT_CONTENTS,ec);
+}
+
+PassRefPtr<DocumentFragment> Range::cloneContents( int &ec )
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return 0;
+ }
+
+ return processContents(CLONE_CONTENTS,ec);
+}
+
+void Range::insertNode(PassRefPtr<Node> newNode, ExceptionCode& ec)
+{
+ ec = 0;
+
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return;
+ }
+
+ if (!newNode) {
+ ec = NOT_FOUND_ERR;
+ return;
+ }
+
+ // NO_MODIFICATION_ALLOWED_ERR: Raised if an ancestor container of either boundary-point of
+ // the Range is read-only.
+ if (containedByReadOnly()) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return;
+ }
+
+ // WRONG_DOCUMENT_ERR: Raised if newParent and the container of the start of the Range were
+ // not created from the same document.
+ if (newNode->document() != m_startContainer->document()) {
+ ec = WRONG_DOCUMENT_ERR;
+ return;
+ }
+
+
+ // HIERARCHY_REQUEST_ERR: Raised if the container of the start of the Range is of a type that
+ // does not allow children of the type of newNode or if newNode is an ancestor of the container.
+
+ // an extra one here - if a text node is going to split, it must have a parent to insert into
+ if (m_startContainer->nodeType() == Node::TEXT_NODE && !m_startContainer->parentNode()) {
+ ec = HIERARCHY_REQUEST_ERR;
+ return;
+ }
+
+ // In the case where the container is a text node, we check against the container's parent, because
+ // text nodes get split up upon insertion.
+ Node *checkAgainst;
+ if (m_startContainer->nodeType() == Node::TEXT_NODE)
+ checkAgainst = m_startContainer->parentNode();
+ else
+ checkAgainst = m_startContainer.get();
+
+ if (newNode->nodeType() == Node::DOCUMENT_FRAGMENT_NODE) {
+ // check each child node, not the DocumentFragment itself
+ Node *c;
+ for (c = newNode->firstChild(); c; c = c->nextSibling()) {
+ if (!checkAgainst->childTypeAllowed(c->nodeType())) {
+ ec = HIERARCHY_REQUEST_ERR;
+ return;
+ }
+ }
+ } else {
+ if (!checkAgainst->childTypeAllowed(newNode->nodeType())) {
+ ec = HIERARCHY_REQUEST_ERR;
+ return;
+ }
+ }
+
+ for (Node *n = m_startContainer.get(); n; n = n->parentNode()) {
+ if (n == newNode) {
+ ec = HIERARCHY_REQUEST_ERR;
+ return;
+ }
+ }
+
+ // INVALID_NODE_TYPE_ERR: Raised if newNode is an Attr, Entity, Notation, or Document node.
+ if (newNode->nodeType() == Node::ATTRIBUTE_NODE ||
+ newNode->nodeType() == Node::ENTITY_NODE ||
+ newNode->nodeType() == Node::NOTATION_NODE ||
+ newNode->nodeType() == Node::DOCUMENT_NODE) {
+ ec = RangeException::INVALID_NODE_TYPE_ERR;
+ return;
+ }
+
+ unsigned endOffsetDelta = 0;
+ if (m_startContainer->nodeType() == Node::TEXT_NODE ||
+ m_startContainer->nodeType() == Node::CDATA_SECTION_NODE) {
+ RefPtr<Text> newText = static_cast<Text*>(m_startContainer.get())->splitText(m_startOffset, ec);
+ if (ec)
+ return;
+
+ if (m_startContainer == m_endContainer)
+ endOffsetDelta = -m_startOffset;
+
+ m_startContainer->parentNode()->insertBefore(newNode, newText.get(), ec);
+ if (ec)
+ return;
+ m_endContainer = newText;
+ } else {
+ if (m_startContainer == m_endContainer) {
+ bool isFragment = newNode->nodeType() == Node::DOCUMENT_FRAGMENT_NODE;
+ endOffsetDelta = isFragment ? newNode->childNodeCount() : 1;
+ }
+
+ m_startContainer->insertBefore(newNode, m_startContainer->childNode(m_startOffset), ec);
+ if (ec)
+ return;
+ }
+ m_endOffset += endOffsetDelta;
+}
+
+String Range::toString(ExceptionCode& ec) const
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return String();
+ }
+
+ Vector<UChar> result;
+
+ Node* pastEnd = pastEndNode();
+ for (Node* n = startNode(); n != pastEnd; n = n->traverseNextNode()) {
+ if (n->nodeType() == Node::TEXT_NODE || n->nodeType() == Node::CDATA_SECTION_NODE) {
+ String data = static_cast<CharacterData*>(n)->data();
+ unsigned length = data.length();
+ unsigned start = (n == m_startContainer) ? min(m_startOffset, length) : 0;
+ unsigned end = (n == m_endContainer) ? min(max(start, m_endOffset), length) : length;
+ result.append(data.characters() + start, end - start);
+ }
+ }
+
+ return String::adopt(result);
+}
+
+String Range::toHTML() const
+{
+ return createMarkup(this);
+}
+
+String Range::text() const
+{
+ if (m_detached)
+ return String();
+
+ // We need to update layout, since plainText uses line boxes in the render tree.
+ // FIXME: As with innerText, we'd like this to work even if there are no render objects.
+ m_startContainer->document()->updateLayout();
+
+ // FIXME: Maybe DOMRange constructor should take const DOMRange*; if it did we would not need this const_cast.
+ return plainText(const_cast<Range *>(this));
+}
+
+PassRefPtr<DocumentFragment> Range::createContextualFragment(const String &html, ExceptionCode& ec) const
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return 0;
+ }
+
+ Node* htmlElement = m_startContainer->isHTMLElement() ? m_startContainer.get() : m_startContainer->parentNode();
+ if (!htmlElement || !htmlElement->isHTMLElement()) {
+ ec = NOT_SUPPORTED_ERR;
+ return 0;
+ }
+
+ RefPtr<DocumentFragment> fragment = static_cast<HTMLElement*>(htmlElement)->createContextualFragment(html);
+ if (!fragment) {
+ ec = NOT_SUPPORTED_ERR;
+ return 0;
+ }
+
+ return fragment.release();
+}
+
+
+void Range::detach(ExceptionCode& ec)
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return;
+ }
+
+ m_startContainer = 0;
+ m_endContainer = 0;
+ m_detached = true;
+}
+
+bool Range::isDetached() const
+{
+ return m_detached;
+}
+
+void Range::checkNodeWOffset(Node* n, int offset, ExceptionCode& ec) const
+{
+ switch (n->nodeType()) {
+ case Node::DOCUMENT_TYPE_NODE:
+ case Node::ENTITY_NODE:
+ case Node::NOTATION_NODE:
+ ec = RangeException::INVALID_NODE_TYPE_ERR;
+ return;
+ case Node::CDATA_SECTION_NODE:
+ case Node::COMMENT_NODE:
+ case Node::TEXT_NODE:
+ if (static_cast<unsigned>(offset) > static_cast<CharacterData*>(n)->length())
+ ec = INDEX_SIZE_ERR;
+ return;
+ case Node::PROCESSING_INSTRUCTION_NODE:
+ if (static_cast<unsigned>(offset) > static_cast<ProcessingInstruction*>(n)->data().length())
+ ec = INDEX_SIZE_ERR;
+ return;
+ case Node::ATTRIBUTE_NODE:
+ case Node::DOCUMENT_FRAGMENT_NODE:
+ case Node::DOCUMENT_NODE:
+ case Node::ELEMENT_NODE:
+ case Node::ENTITY_REFERENCE_NODE:
+ case Node::XPATH_NAMESPACE_NODE:
+ if (static_cast<unsigned>(offset) > n->childNodeCount())
+ ec = INDEX_SIZE_ERR;
+ return;
+ }
+ ASSERT_NOT_REACHED();
+}
+
+void Range::checkNodeBA(Node* n, ExceptionCode& ec) const
+{
+ // INVALID_NODE_TYPE_ERR: Raised if the root container of refNode is not an
+ // Attr, Document or DocumentFragment node or part of a shadow DOM tree
+ // or if refNode is a Document, DocumentFragment, Attr, Entity, or Notation node.
+ Node *root = n;
+ while (root->parentNode())
+ root = root->parentNode();
+
+ if (!(root->nodeType() == Node::ATTRIBUTE_NODE ||
+ root->nodeType() == Node::DOCUMENT_NODE ||
+ root->nodeType() == Node::DOCUMENT_FRAGMENT_NODE ||
+ root->isShadowNode())) {
+ ec = RangeException::INVALID_NODE_TYPE_ERR;
+ return;
+ }
+
+ if( n->nodeType() == Node::DOCUMENT_NODE ||
+ n->nodeType() == Node::DOCUMENT_FRAGMENT_NODE ||
+ n->nodeType() == Node::ATTRIBUTE_NODE ||
+ n->nodeType() == Node::ENTITY_NODE ||
+ n->nodeType() == Node::NOTATION_NODE )
+ ec = RangeException::INVALID_NODE_TYPE_ERR;
+
+}
+
+PassRefPtr<Range> Range::cloneRange(ExceptionCode& ec) const
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return 0;
+ }
+
+ return new Range(m_ownerDocument.get(), m_startContainer.get(), m_startOffset, m_endContainer.get(), m_endOffset);
+}
+
+void Range::setStartAfter( Node *refNode, ExceptionCode& ec)
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return;
+ }
+
+ if (!refNode) {
+ ec = NOT_FOUND_ERR;
+ return;
+ }
+
+ if (refNode->document() != m_ownerDocument) {
+ ec = WRONG_DOCUMENT_ERR;
+ return;
+ }
+
+ ec = 0;
+ checkNodeBA( refNode, ec );
+ if (ec)
+ return;
+
+ setStart(refNode->parentNode(), refNode->nodeIndex() + 1, ec);
+}
+
+void Range::setEndBefore( Node *refNode, ExceptionCode& ec)
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return;
+ }
+
+ if (!refNode) {
+ ec = NOT_FOUND_ERR;
+ return;
+ }
+
+ if (refNode->document() != m_ownerDocument) {
+ ec = WRONG_DOCUMENT_ERR;
+ return;
+ }
+
+ ec = 0;
+ checkNodeBA(refNode, ec);
+ if (ec)
+ return;
+
+ setEnd(refNode->parentNode(), refNode->nodeIndex(), ec);
+}
+
+void Range::setEndAfter( Node *refNode, ExceptionCode& ec)
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return;
+ }
+
+ if (!refNode) {
+ ec = NOT_FOUND_ERR;
+ return;
+ }
+
+ if (refNode->document() != m_ownerDocument) {
+ ec = WRONG_DOCUMENT_ERR;
+ return;
+ }
+
+ ec = 0;
+ checkNodeBA(refNode, ec);
+ if (ec)
+ return;
+
+ setEnd(refNode->parentNode(), refNode->nodeIndex() + 1, ec);
+
+}
+
+void Range::selectNode( Node *refNode, ExceptionCode& ec)
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return;
+ }
+
+ if (!refNode) {
+ ec = NOT_FOUND_ERR;
+ return;
+ }
+
+ // INVALID_NODE_TYPE_ERR: Raised if an ancestor of refNode is an Entity, Notation or
+ // DocumentType node or if refNode is a Document, DocumentFragment, Attr, Entity, or Notation
+ // node.
+ Node *anc;
+ for (anc = refNode->parentNode(); anc; anc = anc->parentNode()) {
+ if (anc->nodeType() == Node::ENTITY_NODE ||
+ anc->nodeType() == Node::NOTATION_NODE ||
+ anc->nodeType() == Node::DOCUMENT_TYPE_NODE) {
+
+ ec = RangeException::INVALID_NODE_TYPE_ERR;
+ return;
+ }
+ }
+
+ if (refNode->nodeType() == Node::DOCUMENT_NODE ||
+ refNode->nodeType() == Node::DOCUMENT_FRAGMENT_NODE ||
+ refNode->nodeType() == Node::ATTRIBUTE_NODE ||
+ refNode->nodeType() == Node::ENTITY_NODE ||
+ refNode->nodeType() == Node::NOTATION_NODE) {
+
+ ec = RangeException::INVALID_NODE_TYPE_ERR;
+ return;
+ }
+
+ ec = 0;
+ setStartBefore( refNode, ec );
+ if (ec)
+ return;
+ setEndAfter( refNode, ec );
+}
+
+void Range::selectNodeContents( Node *refNode, ExceptionCode& ec)
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return;
+ }
+
+ if (!refNode) {
+ ec = NOT_FOUND_ERR;
+ return;
+ }
+
+ // INVALID_NODE_TYPE_ERR: Raised if refNode or an ancestor of refNode is an Entity, Notation
+ // or DocumentType node.
+ Node *n;
+ for (n = refNode; n; n = n->parentNode()) {
+ if (n->nodeType() == Node::ENTITY_NODE ||
+ n->nodeType() == Node::NOTATION_NODE ||
+ n->nodeType() == Node::DOCUMENT_TYPE_NODE) {
+
+ ec = RangeException::INVALID_NODE_TYPE_ERR;
+ return;
+ }
+ }
+
+ m_startContainer = refNode;
+ m_startOffset = 0;
+ m_endContainer = refNode;
+ m_endOffset = maxEndOffset();
+}
+
+void Range::surroundContents(PassRefPtr<Node> passNewParent, ExceptionCode& ec)
+{
+ RefPtr<Node> newParent = passNewParent;
+
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return;
+ }
+
+ if (!newParent) {
+ ec = NOT_FOUND_ERR;
+ return;
+ }
+
+ // INVALID_NODE_TYPE_ERR: Raised if node is an Attr, Entity, DocumentType, Notation,
+ // Document, or DocumentFragment node.
+ switch (newParent->nodeType()) {
+ case Node::ATTRIBUTE_NODE:
+ case Node::DOCUMENT_FRAGMENT_NODE:
+ case Node::DOCUMENT_NODE:
+ case Node::DOCUMENT_TYPE_NODE:
+ case Node::ENTITY_NODE:
+ case Node::NOTATION_NODE:
+ ec = RangeException::INVALID_NODE_TYPE_ERR;
+ return;
+ case Node::CDATA_SECTION_NODE:
+ case Node::COMMENT_NODE:
+ case Node::ELEMENT_NODE:
+ case Node::ENTITY_REFERENCE_NODE:
+ case Node::PROCESSING_INSTRUCTION_NODE:
+ case Node::TEXT_NODE:
+ case Node::XPATH_NAMESPACE_NODE:
+ break;
+ }
+
+ // NO_MODIFICATION_ALLOWED_ERR: Raised if an ancestor container of either boundary-point of
+ // the Range is read-only.
+ if (containedByReadOnly()) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return;
+ }
+
+ // WRONG_DOCUMENT_ERR: Raised if newParent and the container of the start of the Range were
+ // not created from the same document.
+ if (newParent->document() != m_startContainer->document()) {
+ ec = WRONG_DOCUMENT_ERR;
+ return;
+ }
+
+ // BAD_BOUNDARYPOINTS_ERR: Raised if the Range partially selects a non-Text node.
+ if (m_startContainer->nodeType() != Node::TEXT_NODE) {
+ if (m_startOffset > 0 && m_startOffset < maxStartOffset()) {
+ ec = RangeException::BAD_BOUNDARYPOINTS_ERR;
+ return;
+ }
+ }
+ if (m_endContainer->nodeType() != Node::TEXT_NODE) {
+ if (m_endOffset > 0 && m_endOffset < maxEndOffset()) {
+ ec = RangeException::BAD_BOUNDARYPOINTS_ERR;
+ return;
+ }
+ }
+
+ // Raise a HIERARCHY_REQUEST_ERR if m_startContainer doesn't accept children like newParent.
+ Node* parentOfNewParent = m_startContainer.get();
+ // If m_startContainer is a textNode, it will be split and it will be its parent that will
+ // need to accept newParent.
+ if (parentOfNewParent->isTextNode())
+ parentOfNewParent = parentOfNewParent->parentNode();
+ if (!parentOfNewParent->childTypeAllowed(newParent->nodeType())) {
+ ec = HIERARCHY_REQUEST_ERR;
+ return;
+ }
+
+ if (m_startContainer == newParent || m_startContainer->isDescendantOf(newParent.get())) {
+ ec = HIERARCHY_REQUEST_ERR;
+ return;
+ }
+
+ // FIXME: Do we need a check if the node would end up with a child node of a type not
+ // allowed by the type of node?
+
+ ec = 0;
+ while (Node* n = newParent->firstChild()) {
+ newParent->removeChild(n, ec);
+ if (ec)
+ return;
+ }
+ RefPtr<DocumentFragment> fragment = extractContents(ec);
+ if (ec)
+ return;
+ insertNode(newParent, ec);
+ if (ec)
+ return;
+ newParent->appendChild(fragment.release(), ec);
+ if (ec)
+ return;
+ selectNode(newParent.get(), ec);
+}
+
+void Range::setStartBefore( Node *refNode, ExceptionCode& ec)
+{
+ if (m_detached) {
+ ec = INVALID_STATE_ERR;
+ return;
+ }
+
+ if (!refNode) {
+ ec = NOT_FOUND_ERR;
+ return;
+ }
+
+ if (refNode->document() != m_ownerDocument) {
+ ec = WRONG_DOCUMENT_ERR;
+ return;
+ }
+
+ ec = 0;
+ checkNodeBA(refNode, ec);
+ if (ec)
+ return;
+
+ setStart(refNode->parentNode(), refNode->nodeIndex(), ec);
+}
+
+void Range::checkDeleteExtract(ExceptionCode& ec)
+{
+ if (!commonAncestorContainer(ec) || ec)
+ return;
+
+ Node *pastEnd = pastEndNode();
+ for (Node *n = startNode(); n != pastEnd; n = n->traverseNextNode()) {
+ if (n->isReadOnlyNode()) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return;
+ }
+ if (n->nodeType() == Node::DOCUMENT_TYPE_NODE) { // ### is this for only directly under the DF, or anywhere?
+ ec = HIERARCHY_REQUEST_ERR;
+ return;
+ }
+ }
+
+ if (containedByReadOnly()) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return;
+ }
+}
+
+bool Range::containedByReadOnly() const
+{
+ Node *n;
+ for (n = m_startContainer.get(); n; n = n->parentNode()) {
+ if (n->isReadOnlyNode())
+ return true;
+ }
+ for (n = m_endContainer.get(); n; n = n->parentNode()) {
+ if (n->isReadOnlyNode())
+ return true;
+ }
+ return false;
+}
+
+Position Range::startPosition() const
+{
+ return Position(m_startContainer.get(), m_startOffset);
+}
+
+Position Range::endPosition() const
+{
+ return Position(m_endContainer.get(), m_endOffset);
+}
+
+Node *Range::startNode() const
+{
+ if (!m_startContainer)
+ return 0;
+ if (m_startContainer->offsetInCharacters())
+ return m_startContainer.get();
+ Node *child = m_startContainer->childNode(m_startOffset);
+ if (child)
+ return child;
+ if (m_startOffset == 0)
+ return m_startContainer.get();
+ return m_startContainer->traverseNextSibling();
+}
+
+Position Range::editingStartPosition() const
+{
+ // This function is used by range style computations to avoid bugs like:
+ // <rdar://problem/4017641> REGRESSION (Mail): you can only bold/unbold a selection starting from end of line once
+ // It is important to skip certain irrelevant content at the start of the selection, so we do not wind up
+ // with a spurious "mixed" style.
+
+ VisiblePosition visiblePosition(m_startContainer.get(), m_startOffset, VP_DEFAULT_AFFINITY);
+ if (visiblePosition.isNull())
+ return Position();
+
+ ExceptionCode ec = 0;
+ // if the selection is a caret, just return the position, since the style
+ // behind us is relevant
+ if (collapsed(ec))
+ return visiblePosition.deepEquivalent();
+
+ // if the selection starts just before a paragraph break, skip over it
+ if (isEndOfParagraph(visiblePosition))
+ return visiblePosition.next().deepEquivalent().downstream();
+
+ // otherwise, make sure to be at the start of the first selected node,
+ // instead of possibly at the end of the last node before the selection
+ return visiblePosition.deepEquivalent().downstream();
+}
+
+Node *Range::pastEndNode() const
+{
+ if (!m_startContainer || !m_endContainer)
+ return 0;
+ if (m_endContainer->offsetInCharacters())
+ return m_endContainer->traverseNextSibling();
+ Node *child = m_endContainer->childNode(m_endOffset);
+ if (child)
+ return child;
+ return m_endContainer->traverseNextSibling();
+}
+
+IntRect Range::boundingBox()
+{
+ IntRect result;
+ Vector<IntRect> rects;
+ addLineBoxRects(rects);
+ const size_t n = rects.size();
+ for (size_t i = 0; i < n; ++i)
+ result.unite(rects[i]);
+ return result;
+}
+
+void Range::addLineBoxRects(Vector<IntRect>& rects, bool useSelectionHeight)
+{
+ if (!m_startContainer || !m_endContainer)
+ return;
+
+ RenderObject* start = m_startContainer->renderer();
+ RenderObject* end = m_endContainer->renderer();
+ if (!start || !end)
+ return;
+
+ RenderObject* stop = end->nextInPreOrderAfterChildren();
+ for (RenderObject* r = start; r && r != stop; r = r->nextInPreOrder()) {
+ // only ask leaf render objects for their line box rects
+ if (!r->firstChild()) {
+ int startOffset = r == start ? m_startOffset : 0;
+ int endOffset = r == end ? m_endOffset : UINT_MAX;
+ r->addLineBoxRects(rects, startOffset, endOffset, useSelectionHeight);
+ }
+ }
+}
+
+#ifndef NDEBUG
+#define FormatBufferSize 1024
+void Range::formatForDebugger(char *buffer, unsigned length) const
+{
+ String result;
+ String s;
+
+ if (!m_startContainer || !m_endContainer)
+ result = "<empty>";
+ else {
+ char s[FormatBufferSize];
+ result += "from offset ";
+ result += String::number(m_startOffset);
+ result += " of ";
+ m_startContainer->formatForDebugger(s, FormatBufferSize);
+ result += s;
+ result += " to offset ";
+ result += String::number(m_endOffset);
+ result += " of ";
+ m_endContainer->formatForDebugger(s, FormatBufferSize);
+ result += s;
+ }
+
+ strncpy(buffer, result.utf8().data(), length - 1);
+}
+#undef FormatBufferSize
+#endif
+
+bool operator==(const Range &a, const Range &b)
+{
+ if (&a == &b)
+ return true;
+ // Not strictly legal C++, but in practice this can happen, and works fine with GCC.
+ if (!&a || !&b)
+ return false;
+ bool ad = a.isDetached();
+ bool bd = b.isDetached();
+ if (ad && bd)
+ return true;
+ if (ad || bd)
+ return false;
+ int exception = 0;
+ return a.startContainer(exception) == b.startContainer(exception)
+ && a.endContainer(exception) == b.endContainer(exception)
+ && a.startOffset(exception) == b.startOffset(exception)
+ && a.endOffset(exception) == b.endOffset(exception);
+}
+
+PassRefPtr<Range> rangeOfContents(Node* node)
+{
+ ASSERT(node);
+ RefPtr<Range> range = new Range(node->document());
+ int exception = 0;
+ range->selectNodeContents(node, exception);
+ return range.release();
+}
+
+unsigned Range::maxStartOffset() const
+{
+ if (!m_startContainer)
+ return 0;
+ if (!m_startContainer->offsetInCharacters())
+ return m_startContainer->childNodeCount();
+ return m_startContainer->maxCharacterOffset();
+}
+
+unsigned Range::maxEndOffset() const
+{
+ if (!m_endContainer)
+ return 0;
+ if (!m_endContainer->offsetInCharacters())
+ return m_endContainer->childNodeCount();
+ return m_endContainer->maxCharacterOffset();
+}
+
+}
diff --git a/WebCore/dom/Range.h b/WebCore/dom/Range.h
new file mode 100644
index 0000000..7568748
--- /dev/null
+++ b/WebCore/dom/Range.h
@@ -0,0 +1,145 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Gunnstein Lye (gunnstein@netcom.no)
+ * (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
+ * (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Range_h
+#define Range_h
+
+#include <wtf/RefCounted.h>
+#include <wtf/Forward.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+typedef int ExceptionCode;
+
+class DocumentFragment;
+class Document;
+class IntRect;
+class Node;
+class Position;
+class String;
+
+class Range : public RefCounted<Range>
+{
+public:
+ Range(Document*);
+ Range(Document*, Node* startContainer, int startOffset, Node* endContainer, int endOffset);
+ Range(Document*, const Position&, const Position&);
+ ~Range();
+
+ Document* ownerDocument() const { return m_ownerDocument.get(); }
+
+ Node* startContainer(ExceptionCode&) const;
+ int startOffset(ExceptionCode&) const;
+ Node* endContainer(ExceptionCode&) const;
+ int endOffset(ExceptionCode&) const;
+ bool collapsed(ExceptionCode&) const;
+
+ Node* commonAncestorContainer(ExceptionCode&) const;
+ static Node* commonAncestorContainer(Node* containerA, Node* containerB);
+ void setStart(Node* container, int offset, ExceptionCode&);
+ void setEnd(Node* container, int offset, ExceptionCode&);
+ void collapse(bool toStart, ExceptionCode&);
+ bool isPointInRange(Node* refNode, int offset, ExceptionCode& ec);
+ short comparePoint(Node* refNode, int offset, ExceptionCode& ec);
+ enum CompareResults { NODE_BEFORE, NODE_AFTER, NODE_BEFORE_AND_AFTER, NODE_INSIDE };
+ CompareResults compareNode(Node* refNode, ExceptionCode&);
+ enum CompareHow { START_TO_START, START_TO_END, END_TO_END, END_TO_START };
+ short compareBoundaryPoints(CompareHow, const Range* sourceRange, ExceptionCode&) const;
+ static short compareBoundaryPoints(Node* containerA, int offsetA, Node* containerB, int offsetB);
+ static short compareBoundaryPoints(const Position&, const Position&);
+ bool boundaryPointsValid() const;
+ bool intersectsNode(Node* refNode, ExceptionCode&);
+ void deleteContents(ExceptionCode&);
+ PassRefPtr<DocumentFragment> extractContents(ExceptionCode&);
+ PassRefPtr<DocumentFragment> cloneContents(ExceptionCode&);
+ void insertNode(PassRefPtr<Node>, ExceptionCode&);
+ String toString(ExceptionCode&) const;
+
+ String toHTML() const;
+ String text() const;
+
+ PassRefPtr<DocumentFragment> createContextualFragment(const String& html, ExceptionCode&) const;
+
+ void detach(ExceptionCode&);
+ bool isDetached() const;
+ PassRefPtr<Range> cloneRange(ExceptionCode&) const;
+
+ void setStartAfter(Node*, ExceptionCode&);
+ void setEndBefore(Node*, ExceptionCode&);
+ void setEndAfter(Node*, ExceptionCode&);
+ void selectNode(Node*, ExceptionCode&);
+ void selectNodeContents(Node*, ExceptionCode&);
+ void surroundContents(PassRefPtr<Node>, ExceptionCode&);
+ void setStartBefore(Node*, ExceptionCode&);
+
+ enum ActionType {
+ DELETE_CONTENTS,
+ EXTRACT_CONTENTS,
+ CLONE_CONTENTS
+ };
+ PassRefPtr<DocumentFragment> processContents(ActionType, ExceptionCode&);
+
+ Position startPosition() const;
+ Position endPosition() const;
+
+ Node* startNode() const;
+ Node* pastEndNode() const;
+
+ Position editingStartPosition() const;
+
+ IntRect boundingBox();
+ void addLineBoxRects(Vector<IntRect>&, bool useSelectionHeight = false);
+
+#ifndef NDEBUG
+ void formatForDebugger(char* buffer, unsigned length) const;
+#endif
+
+private:
+ RefPtr<Document> m_ownerDocument;
+ RefPtr<Node> m_startContainer;
+ unsigned m_startOffset;
+ RefPtr<Node> m_endContainer;
+ unsigned m_endOffset;
+ bool m_detached;
+
+ void checkNodeWOffset(Node*, int offset, ExceptionCode&) const;
+ void checkNodeBA(Node*, ExceptionCode&) const;
+ void checkDeleteExtract(ExceptionCode&);
+ bool containedByReadOnly() const;
+ unsigned maxStartOffset() const;
+ unsigned maxEndOffset() const;
+};
+
+PassRefPtr<Range> rangeOfContents(Node*);
+
+bool operator==(const Range&, const Range&);
+inline bool operator!=(const Range& a, const Range& b) { return !(a == b); }
+
+} // namespace
+
+#endif
diff --git a/WebCore/dom/Range.idl b/WebCore/dom/Range.idl
new file mode 100644
index 0000000..4344474
--- /dev/null
+++ b/WebCore/dom/Range.idl
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module ranges {
+
+ // Introduced in DOM Level 2:
+ interface [GenerateConstructor] Range {
+
+ readonly attribute Node startContainer
+ getter raises(DOMException);
+ readonly attribute long startOffset
+ getter raises(DOMException);
+ readonly attribute Node endContainer
+ getter raises(DOMException);
+ readonly attribute long endOffset
+ getter raises(DOMException);
+ readonly attribute boolean collapsed
+ getter raises(DOMException);
+ readonly attribute Node commonAncestorContainer
+ getter raises(DOMException);
+
+ [OldStyleObjC] void setStart(in Node refNode,
+ in long offset)
+ raises(RangeException, DOMException);
+ [OldStyleObjC] void setEnd(in Node refNode,
+ in long offset)
+ raises(RangeException, DOMException);
+ void setStartBefore(in Node refNode)
+ raises(RangeException, DOMException);
+ void setStartAfter(in Node refNode)
+ raises(RangeException, DOMException);
+ void setEndBefore(in Node refNode)
+ raises(RangeException, DOMException);
+ void setEndAfter(in Node refNode)
+ raises(RangeException, DOMException);
+ void collapse(in boolean toStart)
+ raises(DOMException);
+ void selectNode(in Node refNode)
+ raises(RangeException, DOMException);
+ void selectNodeContents(in Node refNode)
+ raises(RangeException, DOMException);
+
+ // CompareHow
+ const unsigned short START_TO_START = 0;
+ const unsigned short START_TO_END = 1;
+ const unsigned short END_TO_END = 2;
+ const unsigned short END_TO_START = 3;
+
+ [OldStyleObjC] short compareBoundaryPoints(in CompareHow how,
+ in Range sourceRange)
+ raises(DOMException);
+
+ void deleteContents()
+ raises(DOMException);
+ DocumentFragment extractContents()
+ raises(DOMException);
+ DocumentFragment cloneContents()
+ raises(DOMException);
+ void insertNode(in Node newNode)
+ raises(DOMException, RangeException);
+ void surroundContents(in Node newParent)
+ raises(DOMException, RangeException);
+ Range cloneRange()
+ raises(DOMException);
+ DOMString toString()
+ raises(DOMException);
+
+ void detach()
+ raises(DOMException);
+
+ // extensions
+
+ DocumentFragment createContextualFragment(in DOMString html)
+ raises(DOMException);
+
+ // WebKit extensions
+
+ boolean intersectsNode(in Node refNode)
+ raises(RangeException, DOMException);
+
+ short compareNode(in Node refNode)
+ raises(RangeException, DOMException);
+
+ // CompareResults
+ const unsigned short NODE_BEFORE = 0;
+ const unsigned short NODE_AFTER = 1;
+ const unsigned short NODE_BEFORE_AND_AFTER = 2;
+ const unsigned short NODE_INSIDE = 3;
+
+ short comparePoint(in Node refNode,
+ in long offset)
+ raises(RangeException, DOMException);
+
+ boolean isPointInRange(in Node refNode,
+ in long offset)
+ raises(RangeException, DOMException);
+
+#if !defined(LANGUAGE_JAVASCRIPT)
+ readonly attribute DOMString text;
+#endif
+ };
+
+}
diff --git a/WebCore/dom/RangeException.h b/WebCore/dom/RangeException.h
new file mode 100644
index 0000000..11a35a5
--- /dev/null
+++ b/WebCore/dom/RangeException.h
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 2000 Gunnstein Lye (gunnstein@netcom.no)
+ * (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
+ * (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef RangeException_h
+#define RangeException_h
+
+#include "ExceptionBase.h"
+
+namespace WebCore {
+
+ class RangeException : public ExceptionBase {
+ public:
+ RangeException(const ExceptionCodeDescription& description)
+ : ExceptionBase(description)
+ {
+ }
+
+ static const int RangeExceptionOffset = 200;
+ static const int RangeExceptionMax = 299;
+
+ enum RangeExceptionCode {
+ BAD_BOUNDARYPOINTS_ERR = RangeExceptionOffset + 1,
+ INVALID_NODE_TYPE_ERR
+ };
+ };
+
+} // namespace WebCore
+
+#endif // RangeException_h
diff --git a/WebCore/dom/RangeException.idl b/WebCore/dom/RangeException.idl
new file mode 100644
index 0000000..36cde16
--- /dev/null
+++ b/WebCore/dom/RangeException.idl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module ranges {
+
+ interface [
+ GenerateConstructor
+ ] RangeException {
+
+ readonly attribute unsigned short code;
+ readonly attribute DOMString name;
+ readonly attribute DOMString message;
+
+#if defined(LANGUAGE_JAVASCRIPT)
+ [DontEnum] DOMString toString();
+#endif
+
+ // DOM Level 2
+
+ const unsigned short BAD_BOUNDARYPOINTS_ERR = 1;
+ const unsigned short INVALID_NODE_TYPE_ERR = 2;
+ };
+
+}
diff --git a/WebCore/dom/RegisteredEventListener.cpp b/WebCore/dom/RegisteredEventListener.cpp
new file mode 100644
index 0000000..e995bd0
--- /dev/null
+++ b/WebCore/dom/RegisteredEventListener.cpp
@@ -0,0 +1,46 @@
+/**
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2003, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "RegisteredEventListener.h"
+
+#include "EventListener.h"
+
+namespace WebCore {
+
+RegisteredEventListener::RegisteredEventListener(const AtomicString& eventType, PassRefPtr<EventListener> listener, bool useCapture)
+ : RefCounted<RegisteredEventListener>(0)
+ , m_eventType(eventType)
+ , m_listener(listener)
+ , m_useCapture(useCapture)
+ , m_removed(false)
+{
+}
+
+bool operator==(const RegisteredEventListener& a, const RegisteredEventListener& b)
+{
+ return a.eventType() == b.eventType() && a.listener() == b.listener() && a.useCapture() == b.useCapture();
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/RegisteredEventListener.h b/WebCore/dom/RegisteredEventListener.h
new file mode 100644
index 0000000..b1bb0ef
--- /dev/null
+++ b/WebCore/dom/RegisteredEventListener.h
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef RegisteredEventListener_h
+#define RegisteredEventListener_h
+
+#include "AtomicString.h"
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+ class EventListener;
+
+ class RegisteredEventListener : public RefCounted<RegisteredEventListener> {
+ public:
+ RegisteredEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture);
+
+ const AtomicString& eventType() const { return m_eventType; }
+ EventListener* listener() const { return m_listener.get(); }
+ bool useCapture() const { return m_useCapture; }
+
+ bool removed() const { return m_removed; }
+ void setRemoved(bool removed) { m_removed = removed; }
+
+ private:
+ AtomicString m_eventType;
+ RefPtr<EventListener> m_listener;
+ bool m_useCapture;
+ bool m_removed;
+ };
+
+
+ bool operator==(const RegisteredEventListener&, const RegisteredEventListener&);
+ inline bool operator!=(const RegisteredEventListener& a, const RegisteredEventListener& b) { return !(a == b); }
+
+} // namespace WebCore
+
+#endif // RegisteredEventListener_h
diff --git a/WebCore/dom/SelectorNodeList.cpp b/WebCore/dom/SelectorNodeList.cpp
new file mode 100644
index 0000000..2015a0e
--- /dev/null
+++ b/WebCore/dom/SelectorNodeList.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2007 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "SelectorNodeList.h"
+
+#include "CSSSelector.h"
+#include "CSSStyleSelector.h"
+#include "Document.h"
+#include "Element.h"
+#include "Node.h"
+
+namespace WebCore {
+
+SelectorNodeList::SelectorNodeList(PassRefPtr<Node> rootNode, CSSSelector* querySelector)
+{
+ Document* document = rootNode->document();
+ CSSStyleSelector* styleSelector = document->styleSelector();
+ for (Node* n = rootNode->firstChild(); n; n = n->traverseNextNode(rootNode.get())) {
+ if (n->isElementNode()) {
+ styleSelector->initElementAndPseudoState(static_cast<Element*>(n));
+ for (CSSSelector* selector = querySelector; selector; selector = selector->next()) {
+ if (styleSelector->checkSelector(selector)) {
+ m_nodes.append(n);
+ break;
+ }
+ }
+ }
+ }
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/SelectorNodeList.h b/WebCore/dom/SelectorNodeList.h
new file mode 100644
index 0000000..147e028
--- /dev/null
+++ b/WebCore/dom/SelectorNodeList.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 SelectorNodeList_h
+#define SelectorNodeList_h
+
+#include "StaticNodeList.h"
+#include <wtf/Forward.h>
+
+namespace WebCore {
+
+ class Node;
+ class CSSSelector;
+
+ class SelectorNodeList : public StaticNodeList {
+ public:
+ SelectorNodeList(PassRefPtr<Node> rootNode, CSSSelector*);
+ };
+
+} // namespace WebCore
+
+#endif // SelectorNodeList_h
diff --git a/WebCore/dom/StaticNodeList.cpp b/WebCore/dom/StaticNodeList.cpp
new file mode 100644
index 0000000..3d7c70d
--- /dev/null
+++ b/WebCore/dom/StaticNodeList.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2007 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ */
+
+#include "config.h"
+#include "StaticNodeList.h"
+
+#include "AtomicString.h"
+#include "Node.h"
+#include "Element.h"
+
+namespace WebCore {
+
+unsigned StaticNodeList::length() const
+{
+ return m_nodes.size();
+}
+
+Node* StaticNodeList::item(unsigned index) const
+{
+ if (index < m_nodes.size())
+ return m_nodes[index].get();
+ return 0;
+}
+
+Node* StaticNodeList::itemWithName(const AtomicString& elementId) const
+{
+ size_t length = m_nodes.size();
+ for (size_t i = 0; i < length; ++i) {
+ Node* node = m_nodes[i].get();
+ if (node->isElementNode() && static_cast<Element*>(node)->getIDAttribute() == elementId)
+ return node;
+ }
+
+ return 0;
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/StaticNodeList.h b/WebCore/dom/StaticNodeList.h
new file mode 100644
index 0000000..aacd1ca
--- /dev/null
+++ b/WebCore/dom/StaticNodeList.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2007 Apple 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 StaticNodeList_h
+#define StaticNodeList_h
+
+#include "NodeList.h"
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+ class Node;
+
+ class StaticNodeList : public NodeList {
+ public:
+ // Derived classes should build up the Vector in their constructor.
+ StaticNodeList() { }
+ virtual ~StaticNodeList() { }
+
+ virtual unsigned length() const;
+ virtual Node* item(unsigned index) const;
+ virtual Node* itemWithName(const AtomicString&) const;
+
+ protected:
+ Vector<RefPtr<Node> > m_nodes;
+ };
+
+} // namespace WebCore
+
+#endif // StaticNodeList_h
diff --git a/WebCore/dom/StyleElement.cpp b/WebCore/dom/StyleElement.cpp
new file mode 100644
index 0000000..8280880
--- /dev/null
+++ b/WebCore/dom/StyleElement.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2006, 2007 Rob Buis
+ * Copyright (C) 2008 Apple, Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "StyleElement.h"
+
+#include "Document.h"
+#include "Element.h"
+#include "MappedAttribute.h"
+#include "MediaList.h"
+#include "MediaQueryEvaluator.h"
+
+namespace WebCore {
+
+StyleElement::StyleElement()
+{
+}
+
+StyleSheet* StyleElement::sheet(Element* e)
+{
+ if (!m_sheet)
+ createSheet(e);
+ return m_sheet.get();
+}
+
+void StyleElement::insertedIntoDocument(Document* document, Element* element)
+{
+ process(element);
+}
+
+void StyleElement::removedFromDocument(Document* document)
+{
+ if (m_sheet)
+ document->updateStyleSelector();
+}
+
+void StyleElement::process(Element* e)
+{
+ if (!e || !e->inDocument())
+ return;
+
+ Vector<UChar> text;
+
+ for (Node* c = e->firstChild(); c; c = c->nextSibling())
+ if (c->nodeType() == Node::TEXT_NODE || c->nodeType() == Node::CDATA_SECTION_NODE || c->nodeType() == Node::COMMENT_NODE)
+ append(text, c->nodeValue());
+
+ createSheet(e, String::adopt(text));
+}
+
+void StyleElement::createSheet(Element* e, const String& text)
+{
+ Document* document = e->document();
+ if (m_sheet) {
+ if (static_cast<CSSStyleSheet*>(m_sheet.get())->isLoading())
+ document->removePendingSheet();
+ m_sheet = 0;
+ }
+
+ // If type is empty or CSS, this is a CSS style sheet.
+ const AtomicString& type = this->type();
+ if (type.isEmpty() || (e->isHTMLElement() ? equalIgnoringCase(type, "text/css") : (type == "text/css"))) {
+ RefPtr<MediaList> mediaList = new MediaList((CSSStyleSheet*)0, media(), e->isHTMLElement());
+ MediaQueryEvaluator screenEval("screen", true);
+ MediaQueryEvaluator printEval("print", true);
+ if (screenEval.eval(mediaList.get()) || printEval.eval(mediaList.get())) {
+ document->addPendingSheet();
+ setLoading(true);
+ m_sheet = new CSSStyleSheet(e, String(), document->inputEncoding());
+ m_sheet->parseString(text, !document->inCompatMode());
+ m_sheet->setMedia(mediaList.get());
+ m_sheet->setTitle(e->title());
+ setLoading(false);
+ }
+ }
+
+ if (m_sheet)
+ m_sheet->checkLoaded();
+}
+
+}
diff --git a/WebCore/dom/StyleElement.h b/WebCore/dom/StyleElement.h
new file mode 100644
index 0000000..7f83909
--- /dev/null
+++ b/WebCore/dom/StyleElement.h
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2006, 2007 Rob Buis
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+#ifndef StyleElement_h
+#define StyleElement_h
+
+#include "CSSStyleSheet.h"
+
+namespace WebCore {
+
+class Element;
+
+class StyleElement {
+public:
+ StyleElement();
+ virtual ~StyleElement() {}
+
+protected:
+ StyleSheet* sheet(Element*);
+
+ virtual void setLoading(bool) {}
+
+ virtual const AtomicString& type() const = 0;
+ virtual const AtomicString& media() const = 0;
+
+ void insertedIntoDocument(Document*, Element*);
+ void removedFromDocument(Document*);
+ void process(Element*);
+
+ void createSheet(Element* e, const String& text = String());
+
+protected:
+ RefPtr<CSSStyleSheet> m_sheet;
+};
+
+} //namespace
+
+#endif
diff --git a/WebCore/dom/StyledElement.cpp b/WebCore/dom/StyledElement.cpp
new file mode 100644
index 0000000..6d9a7d7
--- /dev/null
+++ b/WebCore/dom/StyledElement.cpp
@@ -0,0 +1,486 @@
+/**
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Peter Kelly (pmk@post.com)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "StyledElement.h"
+
+#include "CSSStyleSelector.h"
+#include "CSSStyleSheet.h"
+#include "CSSValueKeywords.h"
+#include "ClassNames.h"
+#include "Document.h"
+#include "HTMLNames.h"
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+struct MappedAttributeKey {
+ uint16_t type;
+ StringImpl* name;
+ StringImpl* value;
+ MappedAttributeKey(MappedAttributeEntry t = eNone, StringImpl* n = 0, StringImpl* v = 0)
+ : type(t), name(n), value(v) { }
+};
+
+static inline bool operator==(const MappedAttributeKey& a, const MappedAttributeKey& b)
+ { return a.type == b.type && a.name == b.name && a.value == b.value; }
+
+struct MappedAttributeKeyTraits : WTF::GenericHashTraits<MappedAttributeKey> {
+ static const bool emptyValueIsZero = true;
+ static const bool needsDestruction = false;
+ static MappedAttributeKey deletedValue() { return eLastEntry; }
+};
+
+struct MappedAttributeHash {
+ static unsigned hash(const MappedAttributeKey&);
+ static bool equal(const MappedAttributeKey& a, const MappedAttributeKey& b) { return a == b; }
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+typedef HashMap<MappedAttributeKey, CSSMappedAttributeDeclaration*, MappedAttributeHash, MappedAttributeKeyTraits> MappedAttributeDecls;
+
+static MappedAttributeDecls* mappedAttributeDecls = 0;
+
+CSSMappedAttributeDeclaration* StyledElement::getMappedAttributeDecl(MappedAttributeEntry entryType, Attribute* attr)
+{
+ if (!mappedAttributeDecls)
+ return 0;
+ return mappedAttributeDecls->get(MappedAttributeKey(entryType, attr->name().localName().impl(), attr->value().impl()));
+}
+
+void StyledElement::setMappedAttributeDecl(MappedAttributeEntry entryType, Attribute* attr, CSSMappedAttributeDeclaration* decl)
+{
+ if (!mappedAttributeDecls)
+ mappedAttributeDecls = new MappedAttributeDecls;
+ mappedAttributeDecls->set(MappedAttributeKey(entryType, attr->name().localName().impl(), attr->value().impl()), decl);
+}
+
+void StyledElement::removeMappedAttributeDecl(MappedAttributeEntry entryType,
+ const QualifiedName& attrName, const AtomicString& attrValue)
+{
+ if (!mappedAttributeDecls)
+ return;
+ mappedAttributeDecls->remove(MappedAttributeKey(entryType, attrName.localName().impl(), attrValue.impl()));
+}
+
+void StyledElement::invalidateStyleAttribute()
+{
+ m_isStyleAttributeValid = false;
+}
+
+void StyledElement::updateStyleAttributeIfNeeded() const
+{
+ if (!m_isStyleAttributeValid) {
+ m_isStyleAttributeValid = true;
+ m_synchronizingStyleAttribute = true;
+ if (m_inlineStyleDecl)
+ const_cast<StyledElement*>(this)->setAttribute(styleAttr, m_inlineStyleDecl->cssText());
+ m_synchronizingStyleAttribute = false;
+ }
+}
+
+StyledElement::StyledElement(const QualifiedName& name, Document *doc)
+ : Element(name, doc)
+{
+}
+
+StyledElement::~StyledElement()
+{
+ destroyInlineStyleDecl();
+}
+
+Attribute* StyledElement::createAttribute(const QualifiedName& name, StringImpl* value)
+{
+ return new MappedAttribute(name, value);
+}
+
+void StyledElement::createInlineStyleDecl()
+{
+ m_inlineStyleDecl = new CSSMutableStyleDeclaration;
+ m_inlineStyleDecl->setParent(document()->elementSheet());
+ m_inlineStyleDecl->setNode(this);
+ m_inlineStyleDecl->setStrictParsing(isHTMLElement() && !document()->inCompatMode());
+}
+
+void StyledElement::destroyInlineStyleDecl()
+{
+ if (m_inlineStyleDecl) {
+ m_inlineStyleDecl->setNode(0);
+ m_inlineStyleDecl->setParent(0);
+ m_inlineStyleDecl = 0;
+ }
+}
+
+void StyledElement::attributeChanged(Attribute* attr, bool preserveDecls)
+{
+ MappedAttribute* mappedAttr = static_cast<MappedAttribute*>(attr);
+ if (mappedAttr->decl() && !preserveDecls) {
+ mappedAttr->setDecl(0);
+ setChanged();
+ if (namedAttrMap)
+ mappedAttributes()->declRemoved();
+ }
+
+ bool checkDecl = true;
+ MappedAttributeEntry entry;
+ bool needToParse = mapToEntry(attr->name(), entry);
+ if (preserveDecls) {
+ if (mappedAttr->decl()) {
+ setChanged();
+ if (namedAttrMap)
+ mappedAttributes()->declAdded();
+ checkDecl = false;
+ }
+ }
+ else if (!attr->isNull() && entry != eNone) {
+ CSSMappedAttributeDeclaration* decl = getMappedAttributeDecl(entry, attr);
+ if (decl) {
+ mappedAttr->setDecl(decl);
+ setChanged();
+ if (namedAttrMap)
+ mappedAttributes()->declAdded();
+ checkDecl = false;
+ } else
+ needToParse = true;
+ }
+
+ if (needToParse)
+ parseMappedAttribute(mappedAttr);
+
+ if (entry == eNone && ownerDocument()->attached() && ownerDocument()->styleSelector()->hasSelectorForAttribute(attr->name().localName()))
+ setChanged();
+
+ if (checkDecl && mappedAttr->decl()) {
+ // Add the decl to the table in the appropriate spot.
+ setMappedAttributeDecl(entry, attr, mappedAttr->decl());
+ mappedAttr->decl()->setMappedState(entry, attr->name(), attr->value());
+ mappedAttr->decl()->setParent(0);
+ mappedAttr->decl()->setNode(0);
+ if (namedAttrMap)
+ mappedAttributes()->declAdded();
+ }
+}
+
+bool StyledElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
+{
+ result = eNone;
+ if (attrName == styleAttr)
+ return !m_synchronizingStyleAttribute;
+ return true;
+}
+
+void StyledElement::parseMappedAttribute(MappedAttribute *attr)
+{
+ if (attr->name() == idAttr) {
+ // unique id
+ setHasID(!attr->isNull());
+ if (namedAttrMap) {
+ if (attr->isNull())
+ namedAttrMap->setID(nullAtom);
+ else if (document()->inCompatMode() && !attr->value().impl()->isLower())
+ namedAttrMap->setID(AtomicString(attr->value().string().lower()));
+ else
+ namedAttrMap->setID(attr->value());
+ }
+ setChanged();
+ } else if (attr->name() == classAttr) {
+ // class
+ bool hasClass = false;
+ if (!attr->isEmpty()) {
+ const AtomicString& value = attr->value();
+ unsigned len = value.length();
+ for (unsigned i = 0; i < len; ++i) {
+ if (!isClassWhitespace(value[i])) {
+ hasClass = true;
+ break;
+ }
+ }
+ }
+ setHasClass(hasClass);
+ if (namedAttrMap)
+ mappedAttributes()->parseClassAttribute(attr->value());
+ setChanged();
+ } else if (attr->name() == styleAttr) {
+ if (attr->isNull())
+ destroyInlineStyleDecl();
+ else
+ getInlineStyleDecl()->parseDeclaration(attr->value());
+ m_isStyleAttributeValid = true;
+ setChanged();
+ }
+}
+
+void StyledElement::createAttributeMap() const
+{
+ namedAttrMap = new NamedMappedAttrMap(const_cast<StyledElement*>(this));
+}
+
+CSSMutableStyleDeclaration* StyledElement::getInlineStyleDecl()
+{
+ if (!m_inlineStyleDecl)
+ createInlineStyleDecl();
+ return m_inlineStyleDecl.get();
+}
+
+CSSStyleDeclaration* StyledElement::style()
+{
+ return getInlineStyleDecl();
+}
+
+const ClassNames* StyledElement::getClassNames() const
+{
+ return namedAttrMap ? mappedAttributes()->getClassNames() : 0;
+}
+
+static inline int toHex(UChar c) {
+ return ((c >= '0' && c <= '9') ? (c - '0')
+ : ((c >= 'a' && c <= 'f') ? (c - 'a' + 10)
+ : (( c >= 'A' && c <= 'F') ? (c - 'A' + 10)
+ : -1)));
+}
+
+void StyledElement::addCSSProperty(MappedAttribute* attr, int id, const String &value)
+{
+ if (!attr->decl()) createMappedDecl(attr);
+ attr->decl()->setProperty(id, value, false);
+}
+
+void StyledElement::addCSSProperty(MappedAttribute* attr, int id, int value)
+{
+ if (!attr->decl()) createMappedDecl(attr);
+ attr->decl()->setProperty(id, value, false);
+}
+
+void StyledElement::addCSSStringProperty(MappedAttribute* attr, int id, const String &value, CSSPrimitiveValue::UnitTypes type)
+{
+ if (!attr->decl()) createMappedDecl(attr);
+ attr->decl()->setStringProperty(id, value, type, false);
+}
+
+void StyledElement::addCSSImageProperty(MappedAttribute* attr, int id, const String& url)
+{
+ if (!attr->decl()) createMappedDecl(attr);
+ attr->decl()->setImageProperty(id, url, false);
+}
+
+void StyledElement::addCSSLength(MappedAttribute* attr, int id, const String &value)
+{
+ // FIXME: This function should not spin up the CSS parser, but should instead just figure out the correct
+ // length unit and make the appropriate parsed value.
+ if (!attr->decl())
+ createMappedDecl(attr);
+
+ // strip attribute garbage..
+ StringImpl* v = value.impl();
+ if (v) {
+ unsigned int l = 0;
+
+ while (l < v->length() && (*v)[l] <= ' ')
+ l++;
+
+ for (; l < v->length(); l++) {
+ UChar cc = (*v)[l];
+ if (cc > '9')
+ break;
+ if (cc < '0') {
+ if (cc == '%' || cc == '*')
+ l++;
+ if (cc != '.')
+ break;
+ }
+ }
+
+ if (l != v->length()) {
+ attr->decl()->setLengthProperty(id, v->substring(0, l), false);
+ return;
+ }
+ }
+
+ attr->decl()->setLengthProperty(id, value, false);
+}
+
+/* color parsing that tries to match as close as possible IE 6. */
+void StyledElement::addCSSColor(MappedAttribute* attr, int id, const String& c)
+{
+ // this is the only case no color gets applied in IE.
+ if (!c.length())
+ return;
+
+ if (!attr->decl())
+ createMappedDecl(attr);
+
+ if (attr->decl()->setProperty(id, c, false))
+ return;
+
+ String color = c;
+ // not something that fits the specs.
+
+ // we're emulating IEs color parser here. It maps transparent to black, otherwise it tries to build a rgb value
+ // out of everyhting you put in. The algorithm is experimentally determined, but seems to work for all test cases I have.
+
+ // the length of the color value is rounded up to the next
+ // multiple of 3. each part of the rgb triple then gets one third
+ // of the length.
+ //
+ // Each triplet is parsed byte by byte, mapping
+ // each number to a hex value (0-9a-fA-F to their values
+ // everything else to 0).
+ //
+ // The highest non zero digit in all triplets is remembered, and
+ // used as a normalization point to normalize to values between 0
+ // and 255.
+
+ if (color.lower() != "transparent") {
+ if (color[0] == '#')
+ color.remove(0, 1);
+ int basicLength = (color.length() + 2) / 3;
+ if (basicLength > 1) {
+ // IE ignores colors with three digits or less
+ int colors[3] = { 0, 0, 0 };
+ int component = 0;
+ int pos = 0;
+ int maxDigit = basicLength-1;
+ while (component < 3) {
+ // search forward for digits in the string
+ int numDigits = 0;
+ while (pos < (int)color.length() && numDigits < basicLength) {
+ int hex = toHex(color[pos]);
+ colors[component] = (colors[component] << 4);
+ if (hex > 0) {
+ colors[component] += hex;
+ maxDigit = min(maxDigit, numDigits);
+ }
+ numDigits++;
+ pos++;
+ }
+ while (numDigits++ < basicLength)
+ colors[component] <<= 4;
+ component++;
+ }
+ maxDigit = basicLength - maxDigit;
+
+ // normalize to 00-ff. The highest filled digit counts, minimum is 2 digits
+ maxDigit -= 2;
+ colors[0] >>= 4*maxDigit;
+ colors[1] >>= 4*maxDigit;
+ colors[2] >>= 4*maxDigit;
+ // ASSERT(colors[0] < 0x100 && colors[1] < 0x100 && colors[2] < 0x100);
+
+ color = String::format("#%02x%02x%02x", colors[0], colors[1], colors[2]);
+ if (attr->decl()->setProperty(id, color, false))
+ return;
+ }
+ }
+ attr->decl()->setProperty(id, CSS_VAL_BLACK, false);
+}
+
+void StyledElement::createMappedDecl(MappedAttribute* attr)
+{
+ CSSMappedAttributeDeclaration* decl = new CSSMappedAttributeDeclaration(0);
+ attr->setDecl(decl);
+ decl->setParent(document()->elementSheet());
+ decl->setNode(this);
+ decl->setStrictParsing(false); // Mapped attributes are just always quirky.
+}
+
+// Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's
+// or anything like that.
+const unsigned PHI = 0x9e3779b9U;
+
+// Paul Hsieh's SuperFastHash
+// http://www.azillionmonkeys.com/qed/hash.html
+unsigned MappedAttributeHash::hash(const MappedAttributeKey& key)
+{
+ uint32_t hash = PHI;
+ uint32_t tmp;
+
+ const uint16_t* p;
+
+ p = reinterpret_cast<const uint16_t*>(&key.name);
+ hash += p[0];
+ tmp = (p[1] << 11) ^ hash;
+ hash = (hash << 16) ^ tmp;
+ hash += hash >> 11;
+ ASSERT(sizeof(key.name) == 4 || sizeof(key.name) == 8);
+ if (sizeof(key.name) == 8) {
+ p += 2;
+ hash += p[0];
+ tmp = (p[1] << 11) ^ hash;
+ hash = (hash << 16) ^ tmp;
+ hash += hash >> 11;
+ }
+
+ p = reinterpret_cast<const uint16_t*>(&key.value);
+ hash += p[0];
+ tmp = (p[1] << 11) ^ hash;
+ hash = (hash << 16) ^ tmp;
+ hash += hash >> 11;
+ ASSERT(sizeof(key.value) == 4 || sizeof(key.value) == 8);
+ if (sizeof(key.value) == 8) {
+ p += 2;
+ hash += p[0];
+ tmp = (p[1] << 11) ^ hash;
+ hash = (hash << 16) ^ tmp;
+ hash += hash >> 11;
+ }
+
+ // Handle end case
+ hash += key.type;
+ hash ^= hash << 11;
+ hash += hash >> 17;
+
+ // Force "avalanching" of final 127 bits
+ hash ^= hash << 3;
+ hash += hash >> 5;
+ hash ^= hash << 2;
+ hash += hash >> 15;
+ hash ^= hash << 10;
+
+ // This avoids ever returning a hash code of 0, since that is used to
+ // signal "hash not computed yet", using a value that is likely to be
+ // effectively the same as 0 when the low bits are masked
+ if (hash == 0)
+ hash = 0x80000000;
+
+ return hash;
+}
+
+void StyledElement::copyNonAttributeProperties(const Element *sourceElement)
+{
+ const StyledElement* source = static_cast<const StyledElement*>(sourceElement);
+ if (!source->m_inlineStyleDecl)
+ return;
+
+ *getInlineStyleDecl() = *source->m_inlineStyleDecl;
+ m_isStyleAttributeValid = source->m_isStyleAttributeValid;
+ m_synchronizingStyleAttribute = source->m_synchronizingStyleAttribute;
+
+ Element::copyNonAttributeProperties(sourceElement);
+}
+
+}
diff --git a/WebCore/dom/StyledElement.h b/WebCore/dom/StyledElement.h
new file mode 100644
index 0000000..82df0bf
--- /dev/null
+++ b/WebCore/dom/StyledElement.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Peter Kelly (pmk@post.com)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef StyledElement_h
+#define StyledElement_h
+
+#include "Element.h"
+#include "NamedMappedAttrMap.h"
+
+namespace WebCore {
+
+class CSSMappedAttributeDeclaration;
+class MappedAttribute;
+
+class StyledElement : public Element {
+public:
+ StyledElement(const QualifiedName&, Document*);
+ virtual ~StyledElement();
+
+ virtual bool isStyledElement() const { return true; }
+
+ NamedMappedAttrMap* mappedAttributes() { return static_cast<NamedMappedAttrMap*>(namedAttrMap.get()); }
+ const NamedMappedAttrMap* mappedAttributes() const { return static_cast<NamedMappedAttrMap*>(namedAttrMap.get()); }
+ bool hasMappedAttributes() const { return namedAttrMap && mappedAttributes()->hasMappedAttributes(); }
+ bool isMappedAttribute(const QualifiedName& name) const { MappedAttributeEntry res = eNone; mapToEntry(name, res); return res != eNone; }
+
+ void addCSSLength(MappedAttribute* attr, int id, const String &value);
+ void addCSSProperty(MappedAttribute* attr, int id, const String &value);
+ void addCSSProperty(MappedAttribute* attr, int id, int value);
+ void addCSSStringProperty(MappedAttribute* attr, int id, const String &value, CSSPrimitiveValue::UnitTypes = CSSPrimitiveValue::CSS_STRING);
+ void addCSSImageProperty(MappedAttribute*, int propertyID, const String& url);
+ void addCSSColor(MappedAttribute* attr, int id, const String &c);
+ void createMappedDecl(MappedAttribute* attr);
+
+ static CSSMappedAttributeDeclaration* getMappedAttributeDecl(MappedAttributeEntry type, Attribute* attr);
+ static void setMappedAttributeDecl(MappedAttributeEntry type, Attribute* attr, CSSMappedAttributeDeclaration* decl);
+ static void removeMappedAttributeDecl(MappedAttributeEntry type, const QualifiedName& attrName, const AtomicString& attrValue);
+
+ CSSMutableStyleDeclaration* inlineStyleDecl() const { return m_inlineStyleDecl.get(); }
+ virtual bool canHaveAdditionalAttributeStyleDecls() const { return false; }
+ virtual void additionalAttributeStyleDecls(Vector<CSSMutableStyleDeclaration*>&) {};
+ CSSMutableStyleDeclaration* getInlineStyleDecl();
+ CSSStyleDeclaration* style();
+ void createInlineStyleDecl();
+ void destroyInlineStyleDecl();
+ void invalidateStyleAttribute();
+ virtual void updateStyleAttributeIfNeeded() const;
+
+ virtual const ClassNames* getClassNames() const;
+ virtual void attributeChanged(Attribute*, bool preserveDecls = false);
+ virtual void parseMappedAttribute(MappedAttribute*);
+ virtual bool mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const;
+ virtual void createAttributeMap() const;
+ virtual Attribute* createAttribute(const QualifiedName& name, StringImpl* value);
+
+ virtual void copyNonAttributeProperties(const Element*);
+
+protected:
+ RefPtr<CSSMutableStyleDeclaration> m_inlineStyleDecl;
+};
+
+} //namespace
+
+#endif
diff --git a/WebCore/dom/TagNodeList.cpp b/WebCore/dom/TagNodeList.cpp
new file mode 100644
index 0000000..81ac8e7
--- /dev/null
+++ b/WebCore/dom/TagNodeList.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Trolltech ASA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "TagNodeList.h"
+
+#include "Element.h"
+#include <wtf/Assertions.h>
+
+namespace WebCore {
+
+TagNodeList::TagNodeList(PassRefPtr<Node> rootNode, const AtomicString& namespaceURI, const AtomicString& localName)
+ : DynamicNodeList(rootNode, true)
+ , m_namespaceURI(namespaceURI)
+ , m_localName(localName)
+{
+ ASSERT(m_namespaceURI.isNull() || !m_namespaceURI.isEmpty());
+}
+
+bool TagNodeList::nodeMatches(Node* testNode) const
+{
+ if (!testNode->isElementNode())
+ return false;
+
+ if (m_namespaceURI != starAtom && m_namespaceURI != testNode->namespaceURI())
+ return false;
+
+ return m_localName == starAtom || m_localName == testNode->localName();
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/TagNodeList.h b/WebCore/dom/TagNodeList.h
new file mode 100644
index 0000000..6593a0a
--- /dev/null
+++ b/WebCore/dom/TagNodeList.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2001 Dirk Mueller (mueller@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Trolltech ASA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef TagNodeList_h
+#define TagNodeList_h
+
+#include "AtomicString.h"
+#include "DynamicNodeList.h"
+
+namespace WebCore {
+
+ // NodeList that limits to a particular tag.
+ class TagNodeList : public DynamicNodeList {
+ public:
+ TagNodeList(PassRefPtr<Node> rootNode, const AtomicString& namespaceURI, const AtomicString& localName);
+
+ private:
+ virtual bool nodeMatches(Node*) const;
+
+ AtomicString m_namespaceURI;
+ AtomicString m_localName;
+ };
+
+} // namespace WebCore
+
+#endif // TagNodeList_h
diff --git a/WebCore/dom/Text.cpp b/WebCore/dom/Text.cpp
new file mode 100644
index 0000000..d61214f
--- /dev/null
+++ b/WebCore/dom/Text.cpp
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "Text.h"
+
+#include "CString.h"
+#include "Document.h"
+#include "ExceptionCode.h"
+#include "RenderText.h"
+#include "TextBreakIterator.h"
+
+#if ENABLE(SVG)
+#include "RenderSVGInlineText.h"
+#endif // ENABLE(SVG)
+
+namespace WebCore {
+
+// DOM Section 1.1.1
+
+// ### allow having children in text nodes for entities, comments etc.
+
+Text::Text(Document *doc, const String &_text)
+ : CharacterData(doc, _text)
+{
+}
+
+Text::Text(Document *doc)
+ : CharacterData(doc)
+{
+}
+
+Text::~Text()
+{
+}
+
+PassRefPtr<Text> Text::splitText(unsigned offset, ExceptionCode& ec)
+{
+ ec = 0;
+
+ // FIXME: This does not copy markers
+
+ // INDEX_SIZE_ERR: Raised if the specified offset is negative or greater than
+ // the number of 16-bit units in data.
+ if (offset > m_data->length()) {
+ ec = INDEX_SIZE_ERR;
+ return 0;
+ }
+
+ // NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+ if (isReadOnlyNode()) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return 0;
+ }
+
+ RefPtr<StringImpl> oldStr = m_data;
+ RefPtr<Text> newText = createNew(oldStr->substring(offset));
+ m_data = oldStr->substring(0, offset);
+
+ dispatchModifiedEvent(oldStr.get());
+
+ if (parentNode())
+ parentNode()->insertBefore(newText.get(), nextSibling(), ec);
+ if (ec)
+ return 0;
+
+ if (renderer())
+ static_cast<RenderText*>(renderer())->setText(m_data);
+
+ return newText.release();
+}
+
+static const Text* earliestLogicallyAdjacentTextNode(const Text* t)
+{
+ const Node* n = t;
+ while ((n = n->previousSibling())) {
+ Node::NodeType type = n->nodeType();
+ if (type == Node::TEXT_NODE || type == Node::CDATA_SECTION_NODE) {
+ t = static_cast<const Text*>(n);
+ continue;
+ }
+
+ // We would need to visit EntityReference child text nodes if they existed
+ ASSERT(type != Node::ENTITY_REFERENCE_NODE || !n->hasChildNodes());
+ break;
+ }
+ return t;
+}
+
+static const Text* latestLogicallyAdjacentTextNode(const Text* t)
+{
+ const Node* n = t;
+ while ((n = n->nextSibling())) {
+ Node::NodeType type = n->nodeType();
+ if (type == Node::TEXT_NODE || type == Node::CDATA_SECTION_NODE) {
+ t = static_cast<const Text*>(n);
+ continue;
+ }
+
+ // We would need to visit EntityReference child text nodes if they existed
+ ASSERT(type != Node::ENTITY_REFERENCE_NODE || !n->hasChildNodes());
+ break;
+ }
+ return t;
+}
+
+String Text::wholeText() const
+{
+ const Text* startText = earliestLogicallyAdjacentTextNode(this);
+ const Text* endText = latestLogicallyAdjacentTextNode(this);
+
+ Vector<UChar> result;
+ Node* onePastEndText = endText->nextSibling();
+ for (const Node* n = startText; n != onePastEndText; n = n->nextSibling()) {
+ if (!n->isTextNode())
+ continue;
+ const Text* t = static_cast<const Text*>(n);
+ const String& data = t->data();
+ result.append(data.characters(), data.length());
+ }
+
+ return String::adopt(result);
+}
+
+PassRefPtr<Text> Text::replaceWholeText(const String& newText, ExceptionCode&)
+{
+ // We don't support "read-only" text nodes (no Entity node support)
+ // Thus, we remove all adjacent text nodes, and replace the contents of this one.
+ ASSERT(!isReadOnlyNode());
+ // This method only raises exceptions when dealing with Entity nodes (which we don't support)
+
+ // Protect startText and endText against mutation event handlers removing the last ref
+ RefPtr<Text> startText = const_cast<Text*>(earliestLogicallyAdjacentTextNode(this));
+ RefPtr<Text> endText = const_cast<Text*>(latestLogicallyAdjacentTextNode(this));
+
+ RefPtr<Text> protectedThis(this); // Mutation event handlers could cause our last ref to go away
+ Node* parent = parentNode(); // Protect against mutation handlers moving this node during traversal
+ ExceptionCode ignored = 0;
+ for (RefPtr<Node> n = startText; n && n != this && n->isTextNode() && n->parentNode() == parent;) {
+ RefPtr<Node> nodeToRemove(n.release());
+ n = nodeToRemove->nextSibling();
+ parent->removeChild(nodeToRemove.get(), ignored);
+ }
+
+ if (this != endText) {
+ Node* onePastEndText = endText->nextSibling();
+ for (RefPtr<Node> n = nextSibling(); n && n != onePastEndText && n->isTextNode() && n->parentNode() == parent;) {
+ RefPtr<Node> nodeToRemove(n.release());
+ n = nodeToRemove->nextSibling();
+ parent->removeChild(nodeToRemove.get(), ignored);
+ }
+ }
+
+ if (newText.isEmpty()) {
+ if (parent && parentNode() == parent)
+ parent->removeChild(this, ignored);
+ return 0;
+ }
+
+ setData(newText, ignored);
+ return protectedThis.release();
+}
+
+String Text::nodeName() const
+{
+ return textAtom.string();
+}
+
+Node::NodeType Text::nodeType() const
+{
+ return TEXT_NODE;
+}
+
+PassRefPtr<Node> Text::cloneNode(bool /*deep*/)
+{
+ return document()->createTextNode(m_data);
+}
+
+bool Text::rendererIsNeeded(RenderStyle *style)
+{
+ if (!CharacterData::rendererIsNeeded(style))
+ return false;
+
+ bool onlyWS = containsOnlyWhitespace();
+ if (!onlyWS)
+ return true;
+
+ RenderObject *par = parentNode()->renderer();
+
+ if (par->isTable() || par->isTableRow() || par->isTableSection() || par->isTableCol() || par->isFrameSet())
+ return false;
+
+ if (style->preserveNewline()) // pre/pre-wrap/pre-line always make renderers.
+ return true;
+
+ RenderObject *prev = previousRenderer();
+ if (prev && prev->isBR()) // <span><br/> <br/></span>
+ return false;
+
+ if (par->isInlineFlow()) {
+ // <span><div/> <div/></span>
+ if (prev && !prev->isInline())
+ return false;
+ } else {
+ if (par->isRenderBlock() && !par->childrenInline() && (!prev || !prev->isInline()))
+ return false;
+
+ RenderObject *first = par->firstChild();
+ while (first && first->isFloatingOrPositioned())
+ first = first->nextSibling();
+ RenderObject *next = nextRenderer();
+ if (!first || next == first)
+ // Whitespace at the start of a block just goes away. Don't even
+ // make a render object for this text.
+ return false;
+ }
+
+ return true;
+}
+
+RenderObject *Text::createRenderer(RenderArena *arena, RenderStyle *style)
+{
+#if ENABLE(SVG)
+ if (parentNode()->isSVGElement())
+ return new (arena) RenderSVGInlineText(this, m_data);
+#endif // ENABLE(SVG)
+
+ return new (arena) RenderText(this, m_data);
+}
+
+void Text::attach()
+{
+ createRendererIfNeeded();
+ CharacterData::attach();
+}
+
+void Text::recalcStyle( StyleChange change )
+{
+ if (change != NoChange && parentNode())
+ if (renderer())
+ renderer()->setStyle(parentNode()->renderer()->style());
+ if (changed() && renderer() && renderer()->isText())
+ static_cast<RenderText*>(renderer())->setText(m_data);
+ setChanged(NoStyleChange);
+}
+
+// DOM Section 1.1.1
+bool Text::childTypeAllowed(NodeType)
+{
+ return false;
+}
+
+PassRefPtr<Text> Text::createNew(PassRefPtr<StringImpl> string)
+{
+ return new Text(document(), string);
+}
+
+String Text::toString() const
+{
+ // FIXME: substitute entity references as needed!
+ return nodeValue();
+}
+
+PassRefPtr<Text> Text::createWithLengthLimit(Document* doc, const String& text, unsigned& charsLeft, unsigned maxChars)
+{
+ if (charsLeft == text.length() && charsLeft <= maxChars) {
+ charsLeft = 0;
+ return new Text(doc, text);
+ }
+
+ unsigned start = text.length() - charsLeft;
+ unsigned end = start + std::min(charsLeft, maxChars);
+
+ // check we are not on an unbreakable boundary
+ TextBreakIterator* it = characterBreakIterator(text.characters(), text.length());
+ if (end < text.length() && !isTextBreak(it, end))
+ end = textBreakPreceding(it, end);
+
+ // maxChars of unbreakable characters could lead to infinite loop
+ if (end <= start)
+ end = text.length();
+
+ String nodeText = text.substring(start, end - start);
+ charsLeft = text.length() - end;
+
+ return new Text(doc, nodeText);
+}
+
+#ifndef NDEBUG
+void Text::formatForDebugger(char *buffer, unsigned length) const
+{
+ String result;
+ String s;
+
+ s = nodeName();
+ if (s.length() > 0) {
+ result += s;
+ }
+
+ s = nodeValue();
+ if (s.length() > 0) {
+ if (result.length() > 0)
+ result += "; ";
+ result += "value=";
+ result += s;
+ }
+
+ strncpy(buffer, result.utf8().data(), length - 1);
+}
+#endif
+
+} // namespace WebCore
diff --git a/WebCore/dom/Text.h b/WebCore/dom/Text.h
new file mode 100644
index 0000000..e5282d5
--- /dev/null
+++ b/WebCore/dom/Text.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Text_h
+#define Text_h
+
+#include "CharacterData.h"
+
+namespace WebCore {
+
+const unsigned cTextNodeLengthLimit = 1 << 16;
+
+class Text : public CharacterData {
+public:
+ Text(Document *impl, const String &_text);
+ Text(Document *impl);
+ virtual ~Text();
+
+ // DOM methods & attributes for CharacterData
+
+ PassRefPtr<Text> splitText(unsigned offset, ExceptionCode&);
+
+ // DOM Level 3: http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1312295772
+ String wholeText() const;
+ PassRefPtr<Text> replaceWholeText(const String&, ExceptionCode&);
+
+ // DOM methods overridden from parent classes
+
+ virtual String nodeName() const;
+ virtual NodeType nodeType() const;
+ virtual PassRefPtr<Node> cloneNode(bool deep);
+
+ // Other methods (not part of DOM)
+
+ virtual bool isTextNode() const { return true; }
+ virtual void attach();
+ virtual bool rendererIsNeeded(RenderStyle*);
+ virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+ virtual void recalcStyle(StyleChange = NoChange);
+ virtual bool childTypeAllowed(NodeType);
+
+ virtual String toString() const;
+
+ static PassRefPtr<Text> createWithLengthLimit(Document*, const String&, unsigned& charsLeft, unsigned maxChars = cTextNodeLengthLimit);
+
+#ifndef NDEBUG
+ virtual void formatForDebugger(char* buffer, unsigned length) const;
+#endif
+
+protected:
+ virtual PassRefPtr<Text> createNew(PassRefPtr<StringImpl>);
+};
+
+} // namespace WebCore
+
+#endif // Text_h
diff --git a/WebCore/dom/Text.idl b/WebCore/dom/Text.idl
new file mode 100644
index 0000000..1b0009d
--- /dev/null
+++ b/WebCore/dom/Text.idl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module core {
+
+ interface [
+ GenerateConstructor,
+ InterfaceUUID=4EA6B89C-F8E5-462a-A807-519446123184,
+ ImplementationUUID=CB5D61CB-D30D-486e-9BD7-F42B7611C2E5
+ ] Text : CharacterData {
+
+ // DOM Level 1
+
+ Text splitText(in [IsIndex] unsigned long offset)
+ raises (DOMException);
+
+ // Introduced in DOM Level 3:
+ readonly attribute DOMString wholeText;
+ Text replaceWholeText(in DOMString content)
+ raises(DOMException);
+ };
+
+}
diff --git a/WebCore/dom/TextEvent.cpp b/WebCore/dom/TextEvent.cpp
new file mode 100644
index 0000000..3f48a2d
--- /dev/null
+++ b/WebCore/dom/TextEvent.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2007 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ *
+ */
+
+#include "config.h"
+#include "TextEvent.h"
+
+#include "EventNames.h"
+
+namespace WebCore {
+
+using namespace EventNames;
+
+TextEvent::TextEvent()
+ : m_isLineBreak(false)
+ , m_isBackTab(false)
+{
+}
+
+TextEvent::TextEvent(AbstractView* view, const String& data)
+ : UIEvent(textInputEvent, true, true, view, 0)
+ , m_data(data)
+ , m_isLineBreak(false)
+ , m_isBackTab(false)
+{
+}
+
+TextEvent::~TextEvent()
+{
+}
+
+void TextEvent::initTextEvent(const AtomicString& type, bool canBubble, bool cancelable, AbstractView* view, const String& data)
+{
+ if (dispatched())
+ return;
+
+ initUIEvent(type, canBubble, cancelable, view, 0);
+
+ m_data = data;
+}
+
+bool TextEvent::isTextEvent() const
+{
+ return true;
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/TextEvent.h b/WebCore/dom/TextEvent.h
new file mode 100644
index 0000000..3297a01
--- /dev/null
+++ b/WebCore/dom/TextEvent.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2007 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 TextEvent_h
+#define TextEvent_h
+
+#include "UIEvent.h"
+
+namespace WebCore {
+
+ class TextEvent : public UIEvent {
+ public:
+ TextEvent();
+ TextEvent(AbstractView*, const String& data);
+ virtual ~TextEvent();
+
+ void initTextEvent(const AtomicString& type, bool canBubble, bool cancelable, AbstractView*, const String& data);
+
+ String data() const { return m_data; }
+
+ virtual bool isTextEvent() const;
+
+ // If true, any newline characters in the text are line breaks only, not paragraph separators.
+ bool isLineBreak() const { return m_isLineBreak; }
+ void setIsLineBreak(bool isLineBreak) { m_isLineBreak = isLineBreak; }
+
+ // If true, any tab characters in the text are backtabs.
+ bool isBackTab() const { return m_isBackTab; }
+ void setIsBackTab(bool isBackTab) { m_isBackTab = isBackTab; }
+
+ private:
+ String m_data;
+ bool m_isLineBreak;
+ bool m_isBackTab;
+ };
+
+} // namespace WebCore
+
+#endif // TextEvent_h
diff --git a/WebCore/dom/TextEvent.idl b/WebCore/dom/TextEvent.idl
new file mode 100644
index 0000000..779afd1
--- /dev/null
+++ b/WebCore/dom/TextEvent.idl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2007 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+module events {
+
+ // Introduced in DOM Level 3:
+ interface [
+ GenerateConstructor
+ ] TextEvent : UIEvent {
+
+ readonly attribute DOMString data;
+
+ void initTextEvent(in DOMString typeArg,
+ in boolean canBubbleArg,
+ in boolean cancelableArg,
+ in DOMWindow viewArg,
+ in DOMString dataArg);
+
+ };
+
+}
diff --git a/WebCore/dom/Tokenizer.h b/WebCore/dom/Tokenizer.h
new file mode 100644
index 0000000..1dfaca2
--- /dev/null
+++ b/WebCore/dom/Tokenizer.h
@@ -0,0 +1,78 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2000 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2005, 2006 Apple Computer, Inc.
+ * Copyright (C) 2007 Samuel Weinig (sam@webkit.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Tokenizer_h
+#define Tokenizer_h
+
+namespace WebCore {
+
+ class SegmentedString;
+
+ class Tokenizer {
+ public:
+ Tokenizer(bool viewSourceMode = false)
+ : m_parserStopped(false)
+ , m_inViewSourceMode(viewSourceMode)
+ {
+ }
+
+ virtual ~Tokenizer() { }
+
+ // Script output must be prepended, while new data
+ // received during executing a script must be appended, hence the
+ // extra bool to be able to distinguish between both cases.
+ // document.write() always uses false, while the loader uses true.
+ virtual bool write(const SegmentedString&, bool appendData) = 0;
+ virtual void finish() = 0;
+ virtual bool isWaitingForScripts() const = 0;
+ virtual void stopParsing() { m_parserStopped = true; }
+ virtual bool processingData() const { return false; }
+ virtual int executingScript() const { return 0; }
+
+ virtual bool wantsRawData() const { return false; }
+ virtual bool writeRawData(const char* data, int len) { return false; }
+
+ bool inViewSourceMode() const { return m_inViewSourceMode; }
+ void setInViewSourceMode(bool mode) { m_inViewSourceMode = mode; }
+
+ virtual bool wellFormed() const { return true; }
+
+ virtual int lineNumber() const { return -1; }
+ virtual int columnNumber() const { return -1; }
+
+ virtual void executeScriptsWaitingForStylesheets() {}
+
+ virtual bool isHTMLTokenizer() const { return false; }
+
+ protected:
+ // The tokenizer has buffers, so parsing may continue even after
+ // it stops receiving data. We use m_parserStopped to stop the tokenizer
+ // even when it has buffered data.
+ bool m_parserStopped;
+ bool m_inViewSourceMode;
+ };
+
+} // namespace WebCore
+
+#endif // Tokenizer_h
diff --git a/WebCore/dom/Traversal.cpp b/WebCore/dom/Traversal.cpp
new file mode 100644
index 0000000..d9dd0a7
--- /dev/null
+++ b/WebCore/dom/Traversal.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "Traversal.h"
+
+#include "Node.h"
+#include "NodeFilter.h"
+
+using namespace KJS;
+
+namespace WebCore {
+
+Traversal::Traversal(PassRefPtr<Node> rootNode, unsigned whatToShow, PassRefPtr<NodeFilter> nodeFilter, bool expandEntityReferences)
+ : RefCounted<Traversal>(0)
+ , m_root(rootNode)
+ , m_whatToShow(whatToShow)
+ , m_filter(nodeFilter)
+ , m_expandEntityReferences(expandEntityReferences)
+{
+}
+
+Traversal::~Traversal()
+{
+}
+
+short Traversal::acceptNode(Node* node, JSValue*& exception) const
+{
+ // FIXME: To handle XML properly we would have to check m_expandEntityReferences.
+
+ // The bid twiddling here is done to map DOM node types, which are given as integers from
+ // 1 through 12, to whatToShow bit masks.
+ if (!(((1 << (node->nodeType() - 1)) & m_whatToShow)))
+ return NodeFilter::FILTER_SKIP;
+ if (!m_filter)
+ return NodeFilter::FILTER_ACCEPT;
+ return m_filter->acceptNode(node, exception);
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/Traversal.h b/WebCore/dom/Traversal.h
new file mode 100644
index 0000000..78265e0
--- /dev/null
+++ b/WebCore/dom/Traversal.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Traversal_h
+#define Traversal_h
+
+#include <wtf/Forward.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace KJS {
+ class JSValue;
+}
+
+namespace WebCore {
+
+ class Node;
+ class NodeFilter;
+
+ class Traversal : public RefCounted<Traversal> {
+ public:
+ Traversal(PassRefPtr<Node>, unsigned whatToShow, PassRefPtr<NodeFilter>, bool expandEntityReferences);
+ virtual ~Traversal();
+
+ Node* root() const { return m_root.get(); }
+ unsigned whatToShow() const { return m_whatToShow; }
+ NodeFilter* filter() const { return m_filter.get(); }
+ bool expandEntityReferences() const { return m_expandEntityReferences; }
+
+ protected:
+ short acceptNode(Node*, KJS::JSValue*& jsException) const;
+
+ private:
+ RefPtr<Node> m_root;
+ unsigned m_whatToShow;
+ RefPtr<NodeFilter> m_filter;
+ bool m_expandEntityReferences;
+ };
+
+} // namespace WebCore
+
+#endif // Traversal_h
diff --git a/WebCore/dom/TreeWalker.cpp b/WebCore/dom/TreeWalker.cpp
new file mode 100644
index 0000000..09c1c95
--- /dev/null
+++ b/WebCore/dom/TreeWalker.cpp
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "TreeWalker.h"
+
+#include "ExceptionCode.h"
+#include "Node.h"
+#include "NodeFilter.h"
+#include <wtf/PassRefPtr.h>
+
+using namespace KJS;
+
+namespace WebCore {
+
+TreeWalker::TreeWalker(PassRefPtr<Node> rootNode, unsigned whatToShow, PassRefPtr<NodeFilter> filter, bool expandEntityReferences)
+ : Traversal(rootNode, whatToShow, filter, expandEntityReferences)
+ , m_current(root())
+{
+}
+
+void TreeWalker::setCurrentNode(PassRefPtr<Node> node, ExceptionCode& ec)
+{
+ if (!node) {
+ ec = NOT_SUPPORTED_ERR;
+ return;
+ }
+ m_current = node;
+}
+
+inline Node* TreeWalker::setCurrent(PassRefPtr<Node> node)
+{
+ m_current = node;
+ return m_current.get();
+}
+
+Node* TreeWalker::parentNode(JSValue*& exception)
+{
+ exception = 0;
+ RefPtr<Node> node = m_current;
+ while (node != root()) {
+ node = node->parentNode();
+ if (!node)
+ return 0;
+ short acceptNodeResult = acceptNode(node.get(), exception);
+ if (exception)
+ return 0;
+ if (acceptNodeResult == NodeFilter::FILTER_ACCEPT)
+ return setCurrent(node.release());
+ }
+ return 0;
+}
+
+Node* TreeWalker::firstChild(JSValue*& exception)
+{
+ exception = 0;
+ for (RefPtr<Node> node = m_current->firstChild(); node; ) {
+ short acceptNodeResult = acceptNode(node.get(), exception);
+ if (exception)
+ return 0;
+ switch (acceptNodeResult) {
+ case NodeFilter::FILTER_ACCEPT:
+ m_current = node.release();
+ return m_current.get();
+ case NodeFilter::FILTER_SKIP:
+ if (node->firstChild()) {
+ node = node->firstChild();
+ continue;
+ }
+ break;
+ case NodeFilter::FILTER_REJECT:
+ break;
+ }
+ do {
+ if (node->nextSibling()) {
+ node = node->nextSibling();
+ break;
+ }
+ Node* parent = node->parentNode();
+ if (!parent || parent == root() || parent == m_current)
+ return 0;
+ node = parent;
+ } while (node);
+ }
+ return 0;
+}
+
+Node* TreeWalker::lastChild(JSValue*& exception)
+{
+ exception = 0;
+ for (RefPtr<Node> node = m_current->lastChild(); node; ) {
+ short acceptNodeResult = acceptNode(node.get(), exception);
+ if (exception)
+ return 0;
+ switch (acceptNodeResult) {
+ case NodeFilter::FILTER_ACCEPT:
+ m_current = node.release();
+ return m_current.get();
+ case NodeFilter::FILTER_SKIP:
+ if (node->lastChild()) {
+ node = node->lastChild();
+ continue;
+ }
+ break;
+ case NodeFilter::FILTER_REJECT:
+ break;
+ }
+ do {
+ if (node->previousSibling()) {
+ node = node->previousSibling();
+ break;
+ }
+ Node* parent = node->parentNode();
+ if (!parent || parent == root() || parent == m_current)
+ return 0;
+ node = parent;
+ } while (node);
+ }
+ return 0;
+}
+
+Node* TreeWalker::previousSibling(JSValue*& exception)
+{
+ exception = 0;
+ RefPtr<Node> node = m_current;
+ if (node == root())
+ return 0;
+ while (1) {
+ for (RefPtr<Node> sibling = node->previousSibling(); sibling; ) {
+ short acceptNodeResult = acceptNode(sibling.get(), exception);
+ if (exception)
+ return 0;
+ switch (acceptNodeResult) {
+ case NodeFilter::FILTER_ACCEPT:
+ m_current = sibling.release();
+ return m_current.get();
+ case NodeFilter::FILTER_SKIP:
+ if (sibling->firstChild()) {
+ sibling = sibling->firstChild();
+ continue;
+ }
+ break;
+ case NodeFilter::FILTER_REJECT:
+ break;
+ }
+ sibling = sibling->previousSibling();
+ }
+ node = node->parentNode();
+ if (!node || node == root())
+ return 0;
+ short acceptNodeResult = acceptNode(node.get(), exception);
+ if (exception)
+ return 0;
+ if (acceptNodeResult == NodeFilter::FILTER_ACCEPT)
+ return 0;
+ }
+}
+
+Node* TreeWalker::nextSibling(JSValue*& exception)
+{
+ exception = 0;
+ RefPtr<Node> node = m_current;
+ if (node == root())
+ return 0;
+ while (1) {
+ for (RefPtr<Node> sibling = node->nextSibling(); sibling; ) {
+ short acceptNodeResult = acceptNode(sibling.get(), exception);
+ if (exception)
+ return 0;
+ switch (acceptNodeResult) {
+ case NodeFilter::FILTER_ACCEPT:
+ m_current = sibling.release();
+ return m_current.get();
+ case NodeFilter::FILTER_SKIP:
+ if (sibling->firstChild()) {
+ sibling = sibling->firstChild();
+ continue;
+ }
+ break;
+ case NodeFilter::FILTER_REJECT:
+ break;
+ }
+ sibling = sibling->nextSibling();
+ }
+ node = node->parentNode();
+ if (!node || node == root())
+ return 0;
+ short acceptNodeResult = acceptNode(node.get(), exception);
+ if (exception)
+ return 0;
+ if (acceptNodeResult == NodeFilter::FILTER_ACCEPT)
+ return 0;
+ }
+}
+
+Node* TreeWalker::previousNode(JSValue*& exception)
+{
+ exception = 0;
+ RefPtr<Node> node = m_current;
+ while (node != root()) {
+ while (Node* previousSibling = node->previousSibling()) {
+ node = previousSibling;
+ short acceptNodeResult = acceptNode(node.get(), exception);
+ if (exception)
+ return 0;
+ if (acceptNodeResult == NodeFilter::FILTER_REJECT)
+ continue;
+ while (Node* lastChild = node->lastChild()) {
+ node = lastChild;
+ acceptNodeResult = acceptNode(node.get(), exception);
+ if (exception)
+ return 0;
+ if (acceptNodeResult == NodeFilter::FILTER_ACCEPT)
+ continue;
+ }
+ if (acceptNodeResult == NodeFilter::FILTER_ACCEPT) {
+ m_current = node.release();
+ return m_current.get();
+ }
+ }
+ if (node == root())
+ return 0;
+ Node* parent = node->parentNode();
+ if (!parent)
+ return 0;
+ node = parent;
+ short acceptNodeResult = acceptNode(node.get(), exception);
+ if (exception)
+ return 0;
+ if (acceptNodeResult == NodeFilter::FILTER_ACCEPT)
+ return setCurrent(node.release());
+ }
+ return 0;
+}
+
+Node* TreeWalker::nextNode(JSValue*& exception)
+{
+ exception = 0;
+ RefPtr<Node> node = m_current;
+Children:
+ while (Node* firstChild = node->firstChild()) {
+ node = firstChild;
+ short acceptNodeResult = acceptNode(node.get(), exception);
+ if (exception)
+ return 0;
+ if (acceptNodeResult == NodeFilter::FILTER_ACCEPT)
+ return setCurrent(node.release());
+ if (acceptNodeResult == NodeFilter::FILTER_REJECT)
+ break;
+ }
+ while (Node* nextSibling = node->traverseNextSibling(root())) {
+ node = nextSibling;
+ short acceptNodeResult = acceptNode(node.get(), exception);
+ if (exception)
+ return 0;
+ if (acceptNodeResult == NodeFilter::FILTER_ACCEPT)
+ return setCurrent(node.release());
+ if (acceptNodeResult == NodeFilter::FILTER_SKIP)
+ goto Children;
+ }
+ return 0;
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/TreeWalker.h b/WebCore/dom/TreeWalker.h
new file mode 100644
index 0000000..8b0ea98
--- /dev/null
+++ b/WebCore/dom/TreeWalker.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef TreeWalker_h
+#define TreeWalker_h
+
+#include "Traversal.h"
+
+namespace WebCore {
+
+ typedef int ExceptionCode;
+
+ class TreeWalker : public Traversal {
+ public:
+ TreeWalker(PassRefPtr<Node>, unsigned whatToShow, PassRefPtr<NodeFilter>, bool expandEntityReferences);
+
+ Node* currentNode() const { return m_current.get(); }
+ void setCurrentNode(PassRefPtr<Node>, ExceptionCode&);
+
+ Node* parentNode(KJS::JSValue*& exception);
+ Node* firstChild(KJS::JSValue*& exception);
+ Node* lastChild(KJS::JSValue*& exception);
+ Node* previousSibling(KJS::JSValue*& exception);
+ Node* nextSibling(KJS::JSValue*& exception);
+ Node* previousNode(KJS::JSValue*& exception);
+ Node* nextNode(KJS::JSValue*& exception);
+
+ // For non-JS bindings. Silently ignores the JavaScript exception if any.
+ Node* parentNode() { KJS::JSValue* exception; return parentNode(exception); }
+ Node* firstChild() { KJS::JSValue* exception; return firstChild(exception); }
+ Node* lastChild() { KJS::JSValue* exception; return lastChild(exception); }
+ Node* previousSibling() { KJS::JSValue* exception; return previousSibling(exception); }
+ Node* nextSibling() { KJS::JSValue* exception; return nextSibling(exception); }
+ Node* previousNode() { KJS::JSValue* exception; return previousNode(exception); }
+ Node* nextNode() { KJS::JSValue* exception; return nextNode(exception); }
+
+ private:
+ Node* setCurrent(PassRefPtr<Node>);
+
+ RefPtr<Node> m_current;
+ };
+
+} // namespace WebCore
+
+#endif // TreeWalker_h
diff --git a/WebCore/dom/TreeWalker.idl b/WebCore/dom/TreeWalker.idl
new file mode 100644
index 0000000..4f98d3a
--- /dev/null
+++ b/WebCore/dom/TreeWalker.idl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module traversal {
+
+ // Introduced in DOM Level 2:
+ interface [CustomMarkFunction] TreeWalker {
+ readonly attribute Node root;
+ readonly attribute unsigned long whatToShow;
+ readonly attribute [ObjCIvar] NodeFilter filter;
+ readonly attribute boolean expandEntityReferences;
+ attribute Node currentNode
+ setter raises(DOMException);
+
+ [Custom] Node parentNode();
+ [Custom] Node firstChild();
+ [Custom] Node lastChild();
+ [Custom] Node previousSibling();
+ [Custom] Node nextSibling();
+ [Custom] Node previousNode();
+ [Custom] Node nextNode();
+ };
+
+}
diff --git a/WebCore/dom/UIEvent.cpp b/WebCore/dom/UIEvent.cpp
new file mode 100644
index 0000000..f247eed
--- /dev/null
+++ b/WebCore/dom/UIEvent.cpp
@@ -0,0 +1,99 @@
+/**
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2003, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "UIEvent.h"
+
+#include "DOMWindow.h"
+
+namespace WebCore {
+
+UIEvent::UIEvent()
+ : m_detail(0)
+{
+}
+
+UIEvent::UIEvent(const AtomicString& eventType, bool canBubbleArg, bool cancelableArg, AbstractView* viewArg, int detailArg)
+ : Event(eventType, canBubbleArg, cancelableArg)
+ , m_view(viewArg)
+ , m_detail(detailArg)
+{
+}
+
+UIEvent::~UIEvent()
+{
+}
+
+void UIEvent::initUIEvent(const AtomicString& typeArg, bool canBubbleArg, bool cancelableArg, AbstractView* viewArg, int detailArg)
+{
+ if (dispatched())
+ return;
+
+ initEvent(typeArg, canBubbleArg, cancelableArg);
+
+ m_view = viewArg;
+ m_detail = detailArg;
+}
+
+bool UIEvent::isUIEvent() const
+{
+ return true;
+}
+
+int UIEvent::keyCode() const
+{
+ return 0;
+}
+
+int UIEvent::charCode() const
+{
+ return 0;
+}
+
+int UIEvent::layerX() const
+{
+ return 0;
+}
+
+int UIEvent::layerY() const
+{
+ return 0;
+}
+
+int UIEvent::pageX() const
+{
+ return 0;
+}
+
+int UIEvent::pageY() const
+{
+ return 0;
+}
+
+int UIEvent::which() const
+{
+ return 0;
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/UIEvent.h b/WebCore/dom/UIEvent.h
new file mode 100644
index 0000000..9c5e0cd
--- /dev/null
+++ b/WebCore/dom/UIEvent.h
@@ -0,0 +1,68 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef UIEvent_h
+#define UIEvent_h
+
+#include "Event.h"
+
+namespace WebCore {
+
+ class DOMWindow;
+
+ typedef DOMWindow AbstractView;
+
+ class UIEvent : public Event {
+ public:
+ UIEvent();
+ UIEvent(const AtomicString& type, bool canBubble, bool cancelable, AbstractView* view, int detail);
+ virtual ~UIEvent();
+
+ void initUIEvent(const AtomicString& type, bool canBubble, bool cancelable, AbstractView* view, int detail);
+
+ AbstractView* view() const { return m_view.get(); }
+ int detail() const { return m_detail; }
+
+ virtual bool isUIEvent() const;
+
+ virtual int keyCode() const;
+ virtual int charCode() const;
+
+ virtual int layerX() const;
+ virtual int layerY() const;
+
+ virtual int pageX() const;
+ virtual int pageY() const;
+
+ virtual int which() const;
+
+ private:
+ RefPtr<AbstractView> m_view;
+ int m_detail;
+ };
+
+} // namespace WebCore
+
+#endif // UIEvent_h
diff --git a/WebCore/dom/UIEvent.idl b/WebCore/dom/UIEvent.idl
new file mode 100644
index 0000000..f6eeb8d
--- /dev/null
+++ b/WebCore/dom/UIEvent.idl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module events {
+
+ // Introduced in DOM Level 2:
+ interface [
+ GenerateConstructor
+ ] UIEvent : Event {
+ readonly attribute DOMWindow view;
+ readonly attribute long detail;
+
+ [OldStyleObjC] void initUIEvent(in AtomicString type,
+ in boolean canBubble,
+ in boolean cancelable,
+ in DOMWindow view,
+ in long detail);
+
+ // extentsions
+ readonly attribute long keyCode;
+ readonly attribute long charCode;
+ readonly attribute long layerX;
+ readonly attribute long layerY;
+ readonly attribute long pageX;
+ readonly attribute long pageY;
+ readonly attribute long which;
+ };
+
+}
diff --git a/WebCore/dom/UIEventWithKeyState.cpp b/WebCore/dom/UIEventWithKeyState.cpp
new file mode 100644
index 0000000..d757b60
--- /dev/null
+++ b/WebCore/dom/UIEventWithKeyState.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "UIEventWithKeyState.h"
+
+namespace WebCore {
+
+UIEventWithKeyState* findEventWithKeyState(Event* event)
+{
+ for (Event* e = event; e; e = e->underlyingEvent())
+ if (e->isKeyboardEvent() || e->isMouseEvent())
+ return static_cast<UIEventWithKeyState*>(e);
+ return 0;
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/UIEventWithKeyState.h b/WebCore/dom/UIEventWithKeyState.h
new file mode 100644
index 0000000..9d42129
--- /dev/null
+++ b/WebCore/dom/UIEventWithKeyState.h
@@ -0,0 +1,70 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef UIEventWithKeyState_h
+#define UIEventWithKeyState_h
+
+#include "UIEvent.h"
+
+namespace WebCore {
+
+ class UIEventWithKeyState : public UIEvent {
+ public:
+ UIEventWithKeyState()
+ : m_ctrlKey(false)
+ , m_altKey(false)
+ , m_shiftKey(false)
+ , m_metaKey(false)
+ {
+ }
+
+ UIEventWithKeyState(const AtomicString& type, bool canBubble, bool cancelable, AbstractView* view,
+ int detail, bool ctrlKey, bool altKey, bool shiftKey, bool metaKey)
+ : UIEvent(type, canBubble, cancelable, view, detail)
+ , m_ctrlKey(ctrlKey)
+ , m_altKey(altKey)
+ , m_shiftKey(shiftKey)
+ , m_metaKey(metaKey)
+ {
+ }
+
+ bool ctrlKey() const { return m_ctrlKey; }
+ bool shiftKey() const { return m_shiftKey; }
+ bool altKey() const { return m_altKey; }
+ bool metaKey() const { return m_metaKey; }
+
+ protected:
+ // Expose these so init functions can set them.
+ bool m_ctrlKey : 1;
+ bool m_altKey : 1;
+ bool m_shiftKey : 1;
+ bool m_metaKey : 1;
+ };
+
+ UIEventWithKeyState* findEventWithKeyState(Event*);
+
+} // namespace WebCore
+
+#endif // UIEventWithKeyState_h
diff --git a/WebCore/dom/WheelEvent.cpp b/WebCore/dom/WheelEvent.cpp
new file mode 100644
index 0000000..02b2448
--- /dev/null
+++ b/WebCore/dom/WheelEvent.cpp
@@ -0,0 +1,85 @@
+/**
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2003, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "WheelEvent.h"
+
+#include "EventNames.h"
+
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+using namespace EventNames;
+
+WheelEvent::WheelEvent()
+ : m_wheelDeltaX(0)
+ , m_wheelDeltaY(0)
+{
+}
+
+WheelEvent::WheelEvent(float wheelDeltaX, float wheelDeltaY, AbstractView* view,
+ int screenX, int screenY, int pageX, int pageY,
+ bool ctrlKey, bool altKey, bool shiftKey, bool metaKey)
+ : MouseRelatedEvent(mousewheelEvent,
+ true, true, view, 0, screenX, screenY, pageX, pageY,
+ ctrlKey, altKey, shiftKey, metaKey)
+ , m_wheelDeltaX(lroundf(wheelDeltaX) * 120)
+ , m_wheelDeltaY(lroundf(wheelDeltaY) * 120) // Normalize to the Windows 120 multiple
+{
+ // Rounding delta to zero makes no sense and breaks Google Maps, <http://bugs.webkit.org/show_bug.cgi?id=16078>.
+ if (wheelDeltaX && !m_wheelDeltaX)
+ m_wheelDeltaX = (wheelDeltaX > 0) ? 120 : -120;
+ if (wheelDeltaY && !m_wheelDeltaY)
+ m_wheelDeltaY = (wheelDeltaY > 0) ? 120 : -120;
+}
+
+void WheelEvent::initWheelEvent(int wheelDeltaX, int wheelDeltaY, AbstractView* view,
+ int screenX, int screenY, int pageX, int pageY,
+ bool ctrlKey, bool altKey, bool shiftKey, bool metaKey)
+{
+ if (dispatched())
+ return;
+
+ initUIEvent(mousewheelEvent, true, true, view, 0);
+
+ m_screenX = screenX;
+ m_screenY = screenY;
+ m_ctrlKey = ctrlKey;
+ m_altKey = altKey;
+ m_shiftKey = shiftKey;
+ m_metaKey = metaKey;
+ m_wheelDeltaX = wheelDeltaX;
+ m_wheelDeltaY = wheelDeltaY;
+
+ initCoordinates(pageX, pageY);
+}
+
+
+bool WheelEvent::isWheelEvent() const
+{
+ return true;
+}
+
+} // namespace WebCore
diff --git a/WebCore/dom/WheelEvent.h b/WebCore/dom/WheelEvent.h
new file mode 100644
index 0000000..9d21949
--- /dev/null
+++ b/WebCore/dom/WheelEvent.h
@@ -0,0 +1,61 @@
+/*
+ * This file is part of the DOM implementation for KDE.
+ *
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2001 Tobias Anton (anton@stud.fbi.fh-darmstadt.de)
+ * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef WheelEvent_h
+#define WheelEvent_h
+
+#include "MouseRelatedEvent.h"
+
+namespace WebCore {
+
+ // extension: mouse wheel event
+ class WheelEvent : public MouseRelatedEvent {
+ public:
+ WheelEvent();
+ WheelEvent(float wheelDeltaX, float wheelDeltaY, AbstractView*,
+ int screenX, int screenY, int pageX, int pageY,
+ bool ctrlKey, bool altKey, bool shiftKey, bool metaKey);
+
+ void initWheelEvent(int wheelDeltaX, int wheelDeltaY, AbstractView*,
+ int screenX, int screenY, int pageX, int pageY,
+ bool ctrlKey, bool altKey, bool shiftKey, bool metaKey);
+
+ int wheelDelta() const { if (m_wheelDeltaY == 0) return m_wheelDeltaX; return m_wheelDeltaY; }
+ int wheelDeltaX() const { return m_wheelDeltaX; }
+ int wheelDeltaY() const { return m_wheelDeltaY; }
+
+ // Needed for Objective-C legacy support
+ bool isHorizontal() const { return m_wheelDeltaX; }
+
+ private:
+ virtual bool isWheelEvent() const;
+
+ int m_wheelDeltaX;
+ int m_wheelDeltaY;
+ };
+
+} // namespace WebCore
+
+#endif // WheelEvent_h
diff --git a/WebCore/dom/WheelEvent.idl b/WebCore/dom/WheelEvent.idl
new file mode 100644
index 0000000..1445509
--- /dev/null
+++ b/WebCore/dom/WheelEvent.idl
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+module events {
+
+ // Based off of proposed IDL interface for WheelEvent:
+ interface [
+ GenerateConstructor
+ ] WheelEvent : UIEvent {
+ readonly attribute long screenX;
+ readonly attribute long screenY;
+ readonly attribute long clientX;
+ readonly attribute long clientY;
+ readonly attribute boolean ctrlKey;
+ readonly attribute boolean shiftKey;
+ readonly attribute boolean altKey;
+ readonly attribute boolean metaKey;
+ readonly attribute long wheelDelta;
+ readonly attribute long wheelDeltaX;
+ readonly attribute long wheelDeltaY;
+
+ // WebKit Extensions
+ readonly attribute long offsetX;
+ readonly attribute long offsetY;
+ readonly attribute long x;
+ readonly attribute long y;
+
+#if defined(LANGUAGE_OBJECTIVE_C)
+ readonly attribute boolean isHorizontal;
+#endif /* defined(LANGUAGE_OBJECTIVE_C) */
+
+#if !defined(LANGUAGE_JAVASCRIPT)
+ void initWheelEvent(in long wheelDeltaX,
+ in long wheelDeltaY,
+ in DOMWindow view,
+ in long screenX,
+ in long screenY,
+ in long clientX,
+ in long clientY,
+ in boolean ctrlKey,
+ in boolean altKey,
+ in boolean shiftKey,
+ in boolean metaKey);
+#endif /* !defined(LANGUAGE_JAVASCRIPT) */
+ };
+
+}
diff --git a/WebCore/dom/XMLTokenizer.cpp b/WebCore/dom/XMLTokenizer.cpp
new file mode 100644
index 0000000..fe7c95a
--- /dev/null
+++ b/WebCore/dom/XMLTokenizer.cpp
@@ -0,0 +1,2105 @@
+/*
+ * Copyright (C) 2000 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
+ * Copyright (C) 2007 Samuel Weinig (sam@webkit.org)
+ * Copyright (C) 2007 Trolltech ASA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "XMLTokenizer.h"
+
+#include "CDATASection.h"
+#include "CString.h"
+#include "Cache.h"
+#include "CachedScript.h"
+#include "Comment.h"
+#include "DocLoader.h"
+#include "Document.h"
+#include "DocumentFragment.h"
+#include "DocumentType.h"
+#include "EventNames.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameView.h"
+#include "HTMLNames.h"
+#include "HTMLScriptElement.h"
+#include "HTMLStyleElement.h"
+#include "HTMLTokenizer.h"
+#include "ProcessingInstruction.h"
+#include "ResourceError.h"
+#include "ResourceHandle.h"
+#include "ResourceRequest.h"
+#include "ResourceResponse.h"
+#ifndef USE_QXMLSTREAM
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h>
+#else
+#include <QDebug>
+#endif
+#include <wtf/Platform.h>
+#include <wtf/StringExtras.h>
+#include <wtf/Threading.h>
+#include <wtf/Vector.h>
+
+#if ENABLE(XSLT)
+#include <libxslt/xslt.h>
+#endif
+
+#if ENABLE(SVG)
+#include "SVGNames.h"
+#include "SVGStyleElement.h"
+#include "XLinkNames.h"
+#endif
+
+using namespace std;
+
+namespace WebCore {
+
+using namespace EventNames;
+using namespace HTMLNames;
+
+const int maxErrors = 25;
+
+#ifndef USE_QXMLSTREAM
+class PendingCallbacks {
+public:
+ PendingCallbacks()
+ {
+ m_callbacks.setAutoDelete(true);
+ }
+
+ void appendStartElementNSCallback(const xmlChar* xmlLocalName, const xmlChar* xmlPrefix, const xmlChar* xmlURI, int nb_namespaces,
+ const xmlChar** namespaces, int nb_attributes, int nb_defaulted, const xmlChar** attributes)
+ {
+ PendingStartElementNSCallback* callback = new PendingStartElementNSCallback;
+
+ callback->xmlLocalName = xmlStrdup(xmlLocalName);
+ callback->xmlPrefix = xmlStrdup(xmlPrefix);
+ callback->xmlURI = xmlStrdup(xmlURI);
+ callback->nb_namespaces = nb_namespaces;
+ callback->namespaces = reinterpret_cast<xmlChar**>(xmlMalloc(sizeof(xmlChar*) * nb_namespaces * 2));
+ for (int i = 0; i < nb_namespaces * 2 ; i++)
+ callback->namespaces[i] = xmlStrdup(namespaces[i]);
+ callback->nb_attributes = nb_attributes;
+ callback->nb_defaulted = nb_defaulted;
+ callback->attributes = reinterpret_cast<xmlChar**>(xmlMalloc(sizeof(xmlChar*) * nb_attributes * 5));
+ for (int i = 0; i < nb_attributes; i++) {
+ // Each attribute has 5 elements in the array:
+ // name, prefix, uri, value and an end pointer.
+
+ for (int j = 0; j < 3; j++)
+ callback->attributes[i * 5 + j] = xmlStrdup(attributes[i * 5 + j]);
+
+ int len = attributes[i * 5 + 4] - attributes[i * 5 + 3];
+
+ callback->attributes[i * 5 + 3] = xmlStrndup(attributes[i * 5 + 3], len);
+ callback->attributes[i * 5 + 4] = callback->attributes[i * 5 + 3] + len;
+ }
+
+ m_callbacks.append(callback);
+ }
+
+ void appendEndElementNSCallback()
+ {
+ PendingEndElementNSCallback* callback = new PendingEndElementNSCallback;
+
+ m_callbacks.append(callback);
+ }
+
+ void appendCharactersCallback(const xmlChar* s, int len)
+ {
+ PendingCharactersCallback* callback = new PendingCharactersCallback;
+
+ callback->s = xmlStrndup(s, len);
+ callback->len = len;
+
+ m_callbacks.append(callback);
+ }
+
+ void appendProcessingInstructionCallback(const xmlChar* target, const xmlChar* data)
+ {
+ PendingProcessingInstructionCallback* callback = new PendingProcessingInstructionCallback;
+
+ callback->target = xmlStrdup(target);
+ callback->data = xmlStrdup(data);
+
+ m_callbacks.append(callback);
+ }
+
+ void appendCDATABlockCallback(const xmlChar* s, int len)
+ {
+ PendingCDATABlockCallback* callback = new PendingCDATABlockCallback;
+
+ callback->s = xmlStrndup(s, len);
+ callback->len = len;
+
+ m_callbacks.append(callback);
+ }
+
+ void appendCommentCallback(const xmlChar* s)
+ {
+ PendingCommentCallback* callback = new PendingCommentCallback;
+
+ callback->s = xmlStrdup(s);
+
+ m_callbacks.append(callback);
+ }
+
+ void appendInternalSubsetCallback(const xmlChar* name, const xmlChar* externalID, const xmlChar* systemID)
+ {
+ PendingInternalSubsetCallback* callback = new PendingInternalSubsetCallback;
+
+ callback->name = xmlStrdup(name);
+ callback->externalID = xmlStrdup(externalID);
+ callback->systemID = xmlStrdup(systemID);
+
+ m_callbacks.append(callback);
+ }
+
+ void appendErrorCallback(XMLTokenizer::ErrorType type, const char* message, int lineNumber, int columnNumber)
+ {
+ PendingErrorCallback* callback = new PendingErrorCallback;
+
+ callback->message = strdup(message);
+ callback->type = type;
+ callback->lineNumber = lineNumber;
+ callback->columnNumber = columnNumber;
+
+ m_callbacks.append(callback);
+ }
+
+ void callAndRemoveFirstCallback(XMLTokenizer* tokenizer)
+ {
+ PendingCallback* cb = m_callbacks.getFirst();
+
+ cb->call(tokenizer);
+ m_callbacks.removeFirst();
+ }
+
+ bool isEmpty() const { return m_callbacks.isEmpty(); }
+
+private:
+ struct PendingCallback {
+
+ virtual ~PendingCallback() { }
+
+ virtual void call(XMLTokenizer* tokenizer) = 0;
+ };
+
+ struct PendingStartElementNSCallback : public PendingCallback {
+ virtual ~PendingStartElementNSCallback() {
+ xmlFree(xmlLocalName);
+ xmlFree(xmlPrefix);
+ xmlFree(xmlURI);
+ for (int i = 0; i < nb_namespaces * 2; i++)
+ xmlFree(namespaces[i]);
+ xmlFree(namespaces);
+ for (int i = 0; i < nb_attributes; i++)
+ for (int j = 0; j < 4; j++)
+ xmlFree(attributes[i * 5 + j]);
+ xmlFree(attributes);
+ }
+
+ virtual void call(XMLTokenizer* tokenizer) {
+ tokenizer->startElementNs(xmlLocalName, xmlPrefix, xmlURI,
+ nb_namespaces, (const xmlChar**)namespaces,
+ nb_attributes, nb_defaulted, (const xmlChar**)(attributes));
+ }
+
+ xmlChar* xmlLocalName;
+ xmlChar* xmlPrefix;
+ xmlChar* xmlURI;
+ int nb_namespaces;
+ xmlChar** namespaces;
+ int nb_attributes;
+ int nb_defaulted;
+ xmlChar** attributes;
+ };
+
+ struct PendingEndElementNSCallback : public PendingCallback {
+ virtual void call(XMLTokenizer* tokenizer)
+ {
+ tokenizer->endElementNs();
+ }
+ };
+
+ struct PendingCharactersCallback : public PendingCallback {
+ virtual ~PendingCharactersCallback()
+ {
+ xmlFree(s);
+ }
+
+ virtual void call(XMLTokenizer* tokenizer)
+ {
+ tokenizer->characters(s, len);
+ }
+
+ xmlChar* s;
+ int len;
+ };
+
+ struct PendingProcessingInstructionCallback : public PendingCallback {
+ virtual ~PendingProcessingInstructionCallback()
+ {
+ xmlFree(target);
+ xmlFree(data);
+ }
+
+ virtual void call(XMLTokenizer* tokenizer)
+ {
+ tokenizer->processingInstruction(target, data);
+ }
+
+ xmlChar* target;
+ xmlChar* data;
+ };
+
+ struct PendingCDATABlockCallback : public PendingCallback {
+ virtual ~PendingCDATABlockCallback()
+ {
+ xmlFree(s);
+ }
+
+ virtual void call(XMLTokenizer* tokenizer)
+ {
+ tokenizer->cdataBlock(s, len);
+ }
+
+ xmlChar* s;
+ int len;
+ };
+
+ struct PendingCommentCallback : public PendingCallback {
+ virtual ~PendingCommentCallback()
+ {
+ xmlFree(s);
+ }
+
+ virtual void call(XMLTokenizer* tokenizer)
+ {
+ tokenizer->comment(s);
+ }
+
+ xmlChar* s;
+ };
+
+ struct PendingInternalSubsetCallback : public PendingCallback {
+ virtual ~PendingInternalSubsetCallback()
+ {
+ xmlFree(name);
+ xmlFree(externalID);
+ xmlFree(systemID);
+ }
+
+ virtual void call(XMLTokenizer* tokenizer)
+ {
+ tokenizer->internalSubset(name, externalID, systemID);
+ }
+
+ xmlChar* name;
+ xmlChar* externalID;
+ xmlChar* systemID;
+ };
+
+ struct PendingErrorCallback: public PendingCallback {
+ virtual ~PendingErrorCallback()
+ {
+ free (message);
+ }
+
+ virtual void call(XMLTokenizer* tokenizer)
+ {
+ tokenizer->handleError(type, message, lineNumber, columnNumber);
+ }
+
+ XMLTokenizer::ErrorType type;
+ char* message;
+ int lineNumber;
+ int columnNumber;
+ };
+
+public:
+ DeprecatedPtrList<PendingCallback> m_callbacks;
+};
+// --------------------------------
+
+static int globalDescriptor = 0;
+static DocLoader* globalDocLoader = 0;
+static ThreadIdentifier libxmlLoaderThread = 0;
+
+static int matchFunc(const char* uri)
+{
+ // Only match loads initiated due to uses of libxml2 from within XMLTokenizer to avoid
+ // interfering with client applications that also use libxml2. http://bugs.webkit.org/show_bug.cgi?id=17353
+ return globalDocLoader && currentThread() == libxmlLoaderThread;
+}
+
+class OffsetBuffer {
+public:
+ OffsetBuffer(const Vector<char>& b) : m_buffer(b), m_currentOffset(0) { }
+
+ int readOutBytes(char* outputBuffer, unsigned askedToRead) {
+ unsigned bytesLeft = m_buffer.size() - m_currentOffset;
+ unsigned lenToCopy = min(askedToRead, bytesLeft);
+ if (lenToCopy) {
+ memcpy(outputBuffer, m_buffer.data() + m_currentOffset, lenToCopy);
+ m_currentOffset += lenToCopy;
+ }
+ return lenToCopy;
+ }
+
+private:
+ Vector<char> m_buffer;
+ unsigned m_currentOffset;
+};
+
+static bool shouldAllowExternalLoad(const char* inURI)
+{
+ if (strstr(inURI, "/etc/xml/catalog")
+ || strstr(inURI, "http://www.w3.org/Graphics/SVG") == inURI
+ || strstr(inURI, "http://www.w3.org/TR/xhtml") == inURI)
+ return false;
+ return true;
+}
+static void* openFunc(const char* uri)
+{
+ ASSERT(globalDocLoader);
+ ASSERT(currentThread() == libxmlLoaderThread);
+
+ if (!shouldAllowExternalLoad(uri))
+ return &globalDescriptor;
+
+ ResourceError error;
+ ResourceResponse response;
+ Vector<char> data;
+
+ DocLoader* docLoader = globalDocLoader;
+ globalDocLoader = 0;
+ // FIXME: We should restore the original global error handler as well.
+
+ if (docLoader->frame())
+ docLoader->frame()->loader()->loadResourceSynchronously(KURL(uri), error, response, data);
+
+ globalDocLoader = docLoader;
+
+ return new OffsetBuffer(data);
+}
+
+static int readFunc(void* context, char* buffer, int len)
+{
+ // Do 0-byte reads in case of a null descriptor
+ if (context == &globalDescriptor)
+ return 0;
+
+ OffsetBuffer* data = static_cast<OffsetBuffer*>(context);
+ return data->readOutBytes(buffer, len);
+}
+
+static int writeFunc(void* context, const char* buffer, int len)
+{
+ // Always just do 0-byte writes
+ return 0;
+}
+
+static int closeFunc(void* context)
+{
+ if (context != &globalDescriptor) {
+ OffsetBuffer* data = static_cast<OffsetBuffer*>(context);
+ delete data;
+ }
+ return 0;
+}
+
+static void errorFunc(void*, const char*, ...)
+{
+ // FIXME: It would be nice to display error messages somewhere.
+}
+
+void setLoaderForLibXMLCallbacks(DocLoader* docLoader)
+{
+ globalDocLoader = docLoader;
+}
+
+static xmlParserCtxtPtr createStringParser(xmlSAXHandlerPtr handlers, void* userData)
+{
+ static bool didInit = false;
+ if (!didInit) {
+ xmlInitParser();
+ xmlRegisterInputCallbacks(matchFunc, openFunc, readFunc, closeFunc);
+ xmlRegisterOutputCallbacks(matchFunc, openFunc, writeFunc, closeFunc);
+ libxmlLoaderThread = currentThread();
+ didInit = true;
+ }
+
+ xmlParserCtxtPtr parser = xmlCreatePushParserCtxt(handlers, 0, 0, 0, 0);
+ parser->_private = userData;
+ parser->replaceEntities = true;
+ const UChar BOM = 0xFEFF;
+ const unsigned char BOMHighByte = *reinterpret_cast<const unsigned char*>(&BOM);
+ xmlSwitchEncoding(parser, BOMHighByte == 0xFF ? XML_CHAR_ENCODING_UTF16LE : XML_CHAR_ENCODING_UTF16BE);
+ return parser;
+}
+#endif
+
+#if defined(USE_QXMLSTREAM) && QT_VERSION >= 0x040400
+class EntityResolver : public QXmlStreamEntityResolver
+{
+ virtual QString resolveUndeclaredEntity(const QString &name);
+};
+
+QString EntityResolver::resolveUndeclaredEntity(const QString &name)
+{
+ UChar c = decodeNamedEntity(name.toUtf8().constData());
+ return QString(c);
+}
+#endif
+
+// --------------------------------
+
+XMLTokenizer::XMLTokenizer(Document* _doc, FrameView* _view)
+ : m_doc(_doc)
+ , m_view(_view)
+#ifdef USE_QXMLSTREAM
+ , m_wroteText(false)
+#else
+ , m_context(0)
+#endif
+ , m_currentNode(_doc)
+ , m_currentNodeIsReferenced(false)
+ , m_sawError(false)
+ , m_sawXSLTransform(false)
+ , m_sawFirstElement(false)
+ , m_isXHTMLDocument(false)
+ , m_parserPaused(false)
+ , m_requestingScript(false)
+ , m_finishCalled(false)
+ , m_errorCount(0)
+ , m_lastErrorLine(0)
+ , m_lastErrorColumn(0)
+ , m_pendingScript(0)
+ , m_scriptStartLine(0)
+ , m_parsingFragment(false)
+#ifndef USE_QXMLSTREAM
+ , m_pendingCallbacks(new PendingCallbacks)
+#endif
+{
+#if defined(USE_QXMLSTREAM) && QT_VERSION >= 0x040400
+ m_stream.setEntityResolver(new EntityResolver);
+#endif
+}
+
+XMLTokenizer::XMLTokenizer(DocumentFragment* fragment, Element* parentElement)
+ : m_doc(fragment->document())
+ , m_view(0)
+#ifdef USE_QXMLSTREAM
+ , m_wroteText(false)
+#else
+ , m_context(0)
+#endif
+ , m_currentNode(fragment)
+ , m_currentNodeIsReferenced(fragment)
+ , m_sawError(false)
+ , m_sawXSLTransform(false)
+ , m_sawFirstElement(false)
+ , m_isXHTMLDocument(false)
+ , m_parserPaused(false)
+ , m_requestingScript(false)
+ , m_finishCalled(false)
+ , m_errorCount(0)
+ , m_lastErrorLine(0)
+ , m_lastErrorColumn(0)
+ , m_pendingScript(0)
+ , m_scriptStartLine(0)
+ , m_parsingFragment(true)
+#ifndef USE_QXMLSTREAM
+ , m_pendingCallbacks(new PendingCallbacks)
+#endif
+{
+ if (fragment)
+ fragment->ref();
+ if (m_doc)
+ m_doc->ref();
+
+ // Add namespaces based on the parent node
+ Vector<Element*> elemStack;
+ while (parentElement) {
+ elemStack.append(parentElement);
+
+ Node* n = parentElement->parentNode();
+ if (!n || !n->isElementNode())
+ break;
+ parentElement = static_cast<Element*>(n);
+ }
+
+ if (elemStack.isEmpty())
+ return;
+
+#if !PLATFORM(QT) || QT_VERSION < 0x040400
+ for (Element* element = elemStack.last(); !elemStack.isEmpty(); elemStack.removeLast()) {
+ if (NamedAttrMap* attrs = element->attributes()) {
+ for (unsigned i = 0; i < attrs->length(); i++) {
+ Attribute* attr = attrs->attributeItem(i);
+ if (attr->localName() == "xmlns")
+ m_defaultNamespaceURI = attr->value();
+ else if (attr->prefix() == "xmlns")
+ m_prefixToNamespaceMap.set(attr->localName(), attr->value());
+ }
+ }
+ }
+#else
+ QXmlStreamNamespaceDeclarations namespaces;
+ for (Element* element = elemStack.last(); !elemStack.isEmpty(); elemStack.removeLast()) {
+ if (NamedAttrMap* attrs = element->attributes()) {
+ for (unsigned i = 0; i < attrs->length(); i++) {
+ Attribute* attr = attrs->attributeItem(i);
+ if (attr->localName() == "xmlns")
+ m_defaultNamespaceURI = attr->value();
+ else if (attr->prefix() == "xmlns")
+ namespaces.append(QXmlStreamNamespaceDeclaration(attr->localName(), attr->value()));
+ }
+ }
+ }
+ m_stream.addExtraNamespaceDeclarations(namespaces);
+ m_stream.setEntityResolver(new EntityResolver);
+#endif
+
+ // If the parent element is not in document tree, there may be no xmlns attribute; just default to the parent's namespace.
+ if (m_defaultNamespaceURI.isNull() && !parentElement->inDocument())
+ m_defaultNamespaceURI = parentElement->namespaceURI();
+}
+
+XMLTokenizer::~XMLTokenizer()
+{
+ setCurrentNode(0);
+ if (m_parsingFragment && m_doc)
+ m_doc->deref();
+ if (m_pendingScript)
+ m_pendingScript->deref(this);
+#if defined(USE_QXMLSTREAM) && QT_VERSION >= 0x040400
+ delete m_stream.entityResolver();
+#endif
+}
+
+void XMLTokenizer::setCurrentNode(Node* n)
+{
+ bool nodeNeedsReference = n && n != m_doc;
+ if (nodeNeedsReference)
+ n->ref();
+ if (m_currentNodeIsReferenced)
+ m_currentNode->deref();
+ m_currentNode = n;
+ m_currentNodeIsReferenced = nodeNeedsReference;
+}
+
+bool XMLTokenizer::write(const SegmentedString& s, bool /*appendData*/)
+{
+ String parseString = s.toString();
+
+ if (m_sawXSLTransform || !m_sawFirstElement)
+ m_originalSourceForTransform += parseString;
+
+ if (m_parserStopped || m_sawXSLTransform)
+ return false;
+
+ if (m_parserPaused) {
+ m_pendingSrc.append(s);
+ return false;
+ }
+
+#ifndef USE_QXMLSTREAM
+ if (!m_context)
+ initializeParserContext();
+
+ // libXML throws an error if you try to switch the encoding for an empty string.
+ if (parseString.length()) {
+ // Hack around libxml2's lack of encoding overide support by manually
+ // resetting the encoding to UTF-16 before every chunk. Otherwise libxml
+ // will detect <?xml version="1.0" encoding="<encoding name>"?> blocks
+ // and switch encodings, causing the parse to fail.
+ const UChar BOM = 0xFEFF;
+ const unsigned char BOMHighByte = *reinterpret_cast<const unsigned char*>(&BOM);
+ xmlSwitchEncoding(m_context, BOMHighByte == 0xFF ? XML_CHAR_ENCODING_UTF16LE : XML_CHAR_ENCODING_UTF16BE);
+
+ xmlParseChunk(m_context, reinterpret_cast<const char*>(parseString.characters()), sizeof(UChar) * parseString.length(), 0);
+ }
+#else
+ m_wroteText = true;
+ QString data(parseString);
+ if (!data.isEmpty()) {
+#if QT_VERSION < 0x040400
+ if (!m_sawFirstElement) {
+ int idx = data.indexOf(QLatin1String("<?xml"));
+ if (idx != -1) {
+ int start = idx + 5;
+ int end = data.indexOf(QLatin1String("?>"), start);
+ QString content = data.mid(start, end-start);
+ bool ok = true;
+ HashMap<String, String> attrs = parseAttributes(content, ok);
+ String version = attrs.get("version");
+ String encoding = attrs.get("encoding");
+ ExceptionCode ec = 0;
+ if (!m_parsingFragment) {
+ if (!version.isEmpty())
+ m_doc->setXMLVersion(version, ec);
+ if (!encoding.isEmpty())
+ m_doc->setXMLEncoding(encoding);
+ }
+ }
+ }
+#endif
+ m_stream.addData(data);
+ parse();
+ }
+#endif
+
+ return false;
+}
+#ifndef USE_QXMLSTREAM
+static inline String toString(const xmlChar* str, unsigned len)
+{
+ return UTF8Encoding().decode(reinterpret_cast<const char*>(str), len);
+}
+
+static inline String toString(const xmlChar* str)
+{
+ if (!str)
+ return String();
+
+ return UTF8Encoding().decode(reinterpret_cast<const char*>(str), strlen(reinterpret_cast<const char*>(str)));
+}
+
+struct _xmlSAX2Namespace {
+ const xmlChar* prefix;
+ const xmlChar* uri;
+};
+typedef struct _xmlSAX2Namespace xmlSAX2Namespace;
+
+static inline void handleElementNamespaces(Element* newElement, const xmlChar** libxmlNamespaces, int nb_namespaces, ExceptionCode& ec)
+{
+ xmlSAX2Namespace* namespaces = reinterpret_cast<xmlSAX2Namespace*>(libxmlNamespaces);
+ for(int i = 0; i < nb_namespaces; i++) {
+ String namespaceQName = "xmlns";
+ String namespaceURI = toString(namespaces[i].uri);
+ if (namespaces[i].prefix)
+ namespaceQName = "xmlns:" + toString(namespaces[i].prefix);
+ newElement->setAttributeNS("http://www.w3.org/2000/xmlns/", namespaceQName, namespaceURI, ec);
+ if (ec) // exception setting attributes
+ return;
+ }
+}
+
+struct _xmlSAX2Attributes {
+ const xmlChar* localname;
+ const xmlChar* prefix;
+ const xmlChar* uri;
+ const xmlChar* value;
+ const xmlChar* end;
+};
+typedef struct _xmlSAX2Attributes xmlSAX2Attributes;
+
+static inline void handleElementAttributes(Element* newElement, const xmlChar** libxmlAttributes, int nb_attributes, ExceptionCode& ec)
+{
+ xmlSAX2Attributes* attributes = reinterpret_cast<xmlSAX2Attributes*>(libxmlAttributes);
+ for(int i = 0; i < nb_attributes; i++) {
+ String attrLocalName = toString(attributes[i].localname);
+ int valueLength = (int) (attributes[i].end - attributes[i].value);
+ String attrValue = toString(attributes[i].value, valueLength);
+ String attrPrefix = toString(attributes[i].prefix);
+ String attrURI = attrPrefix.isEmpty() ? String() : toString(attributes[i].uri);
+ String attrQName = attrPrefix.isEmpty() ? attrLocalName : attrPrefix + ":" + attrLocalName;
+
+ newElement->setAttributeNS(attrURI, attrQName, attrValue, ec);
+ if (ec) // exception setting attributes
+ return;
+ }
+}
+
+void XMLTokenizer::startElementNs(const xmlChar* xmlLocalName, const xmlChar* xmlPrefix, const xmlChar* xmlURI, int nb_namespaces,
+ const xmlChar** libxmlNamespaces, int nb_attributes, int nb_defaulted, const xmlChar** libxmlAttributes)
+{
+ if (m_parserStopped)
+ return;
+
+ if (m_parserPaused) {
+ m_pendingCallbacks->appendStartElementNSCallback(xmlLocalName, xmlPrefix, xmlURI, nb_namespaces, libxmlNamespaces,
+ nb_attributes, nb_defaulted, libxmlAttributes);
+ return;
+ }
+
+ m_sawFirstElement = true;
+
+ exitText();
+
+ String localName = toString(xmlLocalName);
+ String uri = toString(xmlURI);
+ String prefix = toString(xmlPrefix);
+
+ if (m_parsingFragment && uri.isNull()) {
+ if (!prefix.isNull())
+ uri = m_prefixToNamespaceMap.get(prefix);
+ else
+ uri = m_defaultNamespaceURI;
+ }
+
+ ExceptionCode ec = 0;
+ QualifiedName qName(prefix, localName, uri);
+ RefPtr<Element> newElement = m_doc->createElement(qName, true, ec);
+ if (!newElement) {
+ stopParsing();
+ return;
+ }
+
+ handleElementNamespaces(newElement.get(), libxmlNamespaces, nb_namespaces, ec);
+ if (ec) {
+ stopParsing();
+ return;
+ }
+
+ handleElementAttributes(newElement.get(), libxmlAttributes, nb_attributes, ec);
+ if (ec) {
+ stopParsing();
+ return;
+ }
+
+ newElement->beginParsingChildren();
+
+ if (newElement->hasTagName(scriptTag))
+ static_cast<HTMLScriptElement*>(newElement.get())->setCreatedByParser(true);
+ else if (newElement->hasTagName(HTMLNames::styleTag))
+ static_cast<HTMLStyleElement*>(newElement.get())->setCreatedByParser(true);
+#if ENABLE(SVG)
+ else if (newElement->hasTagName(SVGNames::styleTag))
+ static_cast<SVGStyleElement*>(newElement.get())->setCreatedByParser(true);
+#endif
+
+ if (newElement->hasTagName(HTMLNames::scriptTag)
+#if ENABLE(SVG)
+ || newElement->hasTagName(SVGNames::scriptTag)
+#endif
+ )
+ m_scriptStartLine = lineNumber();
+
+ if (!m_currentNode->addChild(newElement.get())) {
+ stopParsing();
+ return;
+ }
+
+ setCurrentNode(newElement.get());
+ if (m_view && !newElement->attached())
+ newElement->attach();
+}
+
+void XMLTokenizer::endElementNs()
+{
+ if (m_parserStopped)
+ return;
+
+ if (m_parserPaused) {
+ m_pendingCallbacks->appendEndElementNSCallback();
+ return;
+ }
+
+ exitText();
+
+ Node* n = m_currentNode;
+ RefPtr<Node> parent = n->parentNode();
+ n->finishParsingChildren();
+
+ // don't load external scripts for standalone documents (for now)
+ if (n->isElementNode() && m_view && (static_cast<Element*>(n)->hasTagName(scriptTag)
+#if ENABLE(SVG)
+ || static_cast<Element*>(n)->hasTagName(SVGNames::scriptTag)
+#endif
+ )) {
+
+
+ ASSERT(!m_pendingScript);
+
+ m_requestingScript = true;
+
+ Element* scriptElement = static_cast<Element*>(n);
+ String scriptHref;
+
+ if (static_cast<Element*>(n)->hasTagName(scriptTag))
+ scriptHref = scriptElement->getAttribute(srcAttr);
+#if ENABLE(SVG)
+ else if (static_cast<Element*>(n)->hasTagName(SVGNames::scriptTag))
+ scriptHref = scriptElement->getAttribute(XLinkNames::hrefAttr);
+#endif
+
+ if (!scriptHref.isEmpty()) {
+ // we have a src attribute
+ const AtomicString& charset = scriptElement->getAttribute(charsetAttr);
+ if ((m_pendingScript = m_doc->docLoader()->requestScript(scriptHref, charset))) {
+ m_scriptElement = scriptElement;
+ m_pendingScript->ref(this);
+
+ // m_pendingScript will be 0 if script was already loaded and ref() executed it
+ if (m_pendingScript)
+ pauseParsing();
+ } else
+ m_scriptElement = 0;
+
+ } else {
+ String scriptCode = "";
+ for (Node* child = scriptElement->firstChild(); child; child = child->nextSibling()) {
+ if (child->isTextNode() || child->nodeType() == Node::CDATA_SECTION_NODE)
+ scriptCode += static_cast<CharacterData*>(child)->data();
+ }
+ m_view->frame()->loader()->executeScript(m_doc->url().string(), m_scriptStartLine - 1, scriptCode);
+ }
+
+ m_requestingScript = false;
+ }
+
+ setCurrentNode(parent.get());
+}
+
+void XMLTokenizer::characters(const xmlChar* s, int len)
+{
+ if (m_parserStopped)
+ return;
+
+ if (m_parserPaused) {
+ m_pendingCallbacks->appendCharactersCallback(s, len);
+ return;
+ }
+
+ if (m_currentNode->isTextNode() || enterText())
+ m_bufferedText.append(s, len);
+}
+
+void XMLTokenizer::error(ErrorType type, const char* message, va_list args)
+{
+ if (m_parserStopped)
+ return;
+
+#if PLATFORM(WIN_OS)
+ char m[1024];
+ vsnprintf(m, sizeof(m) - 1, message, args);
+#else
+ char* m;
+ vasprintf(&m, message, args);
+#endif
+
+ if (m_parserPaused)
+ m_pendingCallbacks->appendErrorCallback(type, m, lineNumber(), columnNumber());
+ else
+ handleError(type, m, lineNumber(), columnNumber());
+
+#if !PLATFORM(WIN_OS)
+ free(m);
+#endif
+}
+
+void XMLTokenizer::processingInstruction(const xmlChar* target, const xmlChar* data)
+{
+ if (m_parserStopped)
+ return;
+
+ if (m_parserPaused) {
+ m_pendingCallbacks->appendProcessingInstructionCallback(target, data);
+ return;
+ }
+
+ exitText();
+
+ // ### handle exceptions
+ int exception = 0;
+ RefPtr<ProcessingInstruction> pi = m_doc->createProcessingInstruction(
+ toString(target), toString(data), exception);
+ if (exception)
+ return;
+
+ if (!m_currentNode->addChild(pi.get()))
+ return;
+ if (m_view && !pi->attached())
+ pi->attach();
+
+ // don't load stylesheets for standalone documents
+ if (m_doc->frame()) {
+ m_sawXSLTransform = !m_sawFirstElement && !pi->checkStyleSheet();
+#if ENABLE(XSLT)
+ // Pretend we didn't see this PI if we're the result of a transform.
+ if (m_sawXSLTransform && !m_doc->transformSourceDocument())
+#else
+ if (m_sawXSLTransform)
+#endif
+ // Stop the SAX parser.
+ stopParsing();
+ }
+}
+
+void XMLTokenizer::cdataBlock(const xmlChar* s, int len)
+{
+ if (m_parserStopped)
+ return;
+
+ if (m_parserPaused) {
+ m_pendingCallbacks->appendCDATABlockCallback(s, len);
+ return;
+ }
+
+ exitText();
+
+ RefPtr<Node> newNode = new CDATASection(m_doc, toString(s, len));
+ if (!m_currentNode->addChild(newNode.get()))
+ return;
+ if (m_view && !newNode->attached())
+ newNode->attach();
+}
+
+void XMLTokenizer::comment(const xmlChar* s)
+{
+ if (m_parserStopped)
+ return;
+
+ if (m_parserPaused) {
+ m_pendingCallbacks->appendCommentCallback(s);
+ return;
+ }
+
+ exitText();
+
+ RefPtr<Node> newNode = new Comment(m_doc, toString(s));
+ m_currentNode->addChild(newNode.get());
+ if (m_view && !newNode->attached())
+ newNode->attach();
+}
+
+void XMLTokenizer::startDocument(const xmlChar* version, const xmlChar* encoding, int standalone)
+{
+ ExceptionCode ec = 0;
+
+ if (version)
+ m_doc->setXMLVersion(toString(version), ec);
+ m_doc->setXMLStandalone(standalone == 1, ec); // possible values are 0, 1, and -1
+ if (encoding)
+ m_doc->setXMLEncoding(toString(encoding));
+}
+
+void XMLTokenizer::endDocument()
+{
+ exitText();
+}
+
+void XMLTokenizer::internalSubset(const xmlChar* name, const xmlChar* externalID, const xmlChar* systemID)
+{
+ if (m_parserStopped)
+ return;
+
+ if (m_parserPaused) {
+ m_pendingCallbacks->appendInternalSubsetCallback(name, externalID, systemID);
+ return;
+ }
+
+ if (m_doc)
+ m_doc->addChild(new DocumentType(m_doc, toString(name), toString(externalID), toString(systemID)));
+}
+
+static inline XMLTokenizer* getTokenizer(void* closure)
+{
+ xmlParserCtxtPtr ctxt = static_cast<xmlParserCtxtPtr>(closure);
+ return static_cast<XMLTokenizer*>(ctxt->_private);
+}
+
+// This is a hack around http://bugzilla.gnome.org/show_bug.cgi?id=159219
+// Otherwise libxml seems to call all the SAX callbacks twice for any replaced entity.
+static inline bool hackAroundLibXMLEntityBug(void* closure)
+{
+#if LIBXML_VERSION >= 20627
+ // This bug has been fixed in libxml 2.6.27.
+ return false;
+#else
+ return static_cast<xmlParserCtxtPtr>(closure)->node;
+#endif
+}
+
+static void startElementNsHandler(void* closure, const xmlChar* localname, const xmlChar* prefix, const xmlChar* uri, int nb_namespaces, const xmlChar** namespaces, int nb_attributes, int nb_defaulted, const xmlChar** libxmlAttributes)
+{
+ if (hackAroundLibXMLEntityBug(closure))
+ return;
+
+ getTokenizer(closure)->startElementNs(localname, prefix, uri, nb_namespaces, namespaces, nb_attributes, nb_defaulted, libxmlAttributes);
+}
+
+static void endElementNsHandler(void* closure, const xmlChar* localname, const xmlChar* prefix, const xmlChar* uri)
+{
+ if (hackAroundLibXMLEntityBug(closure))
+ return;
+
+ getTokenizer(closure)->endElementNs();
+}
+
+static void charactersHandler(void* closure, const xmlChar* s, int len)
+{
+ if (hackAroundLibXMLEntityBug(closure))
+ return;
+
+ getTokenizer(closure)->characters(s, len);
+}
+
+static void processingInstructionHandler(void* closure, const xmlChar* target, const xmlChar* data)
+{
+ if (hackAroundLibXMLEntityBug(closure))
+ return;
+
+ getTokenizer(closure)->processingInstruction(target, data);
+}
+
+static void cdataBlockHandler(void* closure, const xmlChar* s, int len)
+{
+ if (hackAroundLibXMLEntityBug(closure))
+ return;
+
+ getTokenizer(closure)->cdataBlock(s, len);
+}
+
+static void commentHandler(void* closure, const xmlChar* comment)
+{
+ if (hackAroundLibXMLEntityBug(closure))
+ return;
+
+ getTokenizer(closure)->comment(comment);
+}
+
+WTF_ATTRIBUTE_PRINTF(2, 3)
+static void warningHandler(void* closure, const char* message, ...)
+{
+ va_list args;
+ va_start(args, message);
+ getTokenizer(closure)->error(XMLTokenizer::warning, message, args);
+ va_end(args);
+}
+
+WTF_ATTRIBUTE_PRINTF(2, 3)
+static void fatalErrorHandler(void* closure, const char* message, ...)
+{
+ va_list args;
+ va_start(args, message);
+ getTokenizer(closure)->error(XMLTokenizer::fatal, message, args);
+ va_end(args);
+}
+
+WTF_ATTRIBUTE_PRINTF(2, 3)
+static void normalErrorHandler(void* closure, const char* message, ...)
+{
+ va_list args;
+ va_start(args, message);
+ getTokenizer(closure)->error(XMLTokenizer::nonFatal, message, args);
+ va_end(args);
+}
+
+// Using a global variable entity and marking it XML_INTERNAL_PREDEFINED_ENTITY is
+// a hack to avoid malloc/free. Using a global variable like this could cause trouble
+// if libxml implementation details were to change
+static xmlChar sharedXHTMLEntityResult[5] = {0,0,0,0,0};
+static xmlEntity sharedXHTMLEntity = {
+ 0, XML_ENTITY_DECL, 0, 0, 0, 0, 0, 0, 0,
+ sharedXHTMLEntityResult, sharedXHTMLEntityResult, 0,
+ XML_INTERNAL_PREDEFINED_ENTITY, 0, 0, 0, 0, 0
+};
+
+static xmlEntityPtr getXHTMLEntity(const xmlChar* name)
+{
+ UChar c = decodeNamedEntity(reinterpret_cast<const char*>(name));
+ if (!c)
+ return 0;
+
+ CString value = String(&c, 1).utf8();
+ ASSERT(value.length() < 5);
+ sharedXHTMLEntity.length = value.length();
+ sharedXHTMLEntity.name = name;
+ memcpy(sharedXHTMLEntityResult, value.data(), sharedXHTMLEntity.length + 1);
+
+ return &sharedXHTMLEntity;
+}
+
+static xmlEntityPtr getEntityHandler(void* closure, const xmlChar* name)
+{
+ xmlParserCtxtPtr ctxt = static_cast<xmlParserCtxtPtr>(closure);
+ xmlEntityPtr ent = xmlGetPredefinedEntity(name);
+ if (ent) {
+ ent->etype = XML_INTERNAL_PREDEFINED_ENTITY;
+ return ent;
+ }
+
+ ent = xmlGetDocEntity(ctxt->myDoc, name);
+ if (!ent && getTokenizer(closure)->isXHTMLDocument()) {
+ ent = getXHTMLEntity(name);
+ if (ent)
+ ent->etype = XML_INTERNAL_GENERAL_ENTITY;
+ }
+
+ return ent;
+}
+
+static void startDocumentHandler(void* closure)
+{
+ xmlParserCtxt* ctxt = static_cast<xmlParserCtxt*>(closure);
+ getTokenizer(closure)->startDocument(ctxt->version, ctxt->encoding, ctxt->standalone);
+ xmlSAX2StartDocument(closure);
+}
+
+static void endDocumentHandler(void* closure)
+{
+ getTokenizer(closure)->endDocument();
+ xmlSAX2EndDocument(closure);
+}
+
+static void internalSubsetHandler(void* closure, const xmlChar* name, const xmlChar* externalID, const xmlChar* systemID)
+{
+ getTokenizer(closure)->internalSubset(name, externalID, systemID);
+ xmlSAX2InternalSubset(closure, name, externalID, systemID);
+}
+
+static void externalSubsetHandler(void* closure, const xmlChar* name, const xmlChar* externalId, const xmlChar* systemId)
+{
+ String extId = toString(externalId);
+ if ((extId == "-//W3C//DTD XHTML 1.0 Transitional//EN")
+ || (extId == "-//W3C//DTD XHTML 1.1//EN")
+ || (extId == "-//W3C//DTD XHTML 1.0 Strict//EN")
+ || (extId == "-//W3C//DTD XHTML 1.0 Frameset//EN")
+ || (extId == "-//W3C//DTD XHTML Basic 1.0//EN")
+ || (extId == "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN")
+ || (extId == "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN")
+ || (extId == "-//WAPFORUM//DTD XHTML Mobile 1.0//EN"))
+ getTokenizer(closure)->setIsXHTMLDocument(true); // controls if we replace entities or not.
+}
+
+static void ignorableWhitespaceHandler(void* ctx, const xmlChar* ch, int len)
+{
+ // nothing to do, but we need this to work around a crasher
+ // http://bugzilla.gnome.org/show_bug.cgi?id=172255
+ // http://bugs.webkit.org/show_bug.cgi?id=5792
+}
+#endif
+
+void XMLTokenizer::handleError(ErrorType type, const char* m, int lineNumber, int columnNumber)
+{
+ if (type == fatal || (m_errorCount < maxErrors && m_lastErrorLine != lineNumber && m_lastErrorColumn != columnNumber)) {
+ switch (type) {
+ case warning:
+ m_errorMessages += String::format("warning on line %d at column %d: %s", lineNumber, columnNumber, m);
+ break;
+ case fatal:
+ case nonFatal:
+ m_errorMessages += String::format("error on line %d at column %d: %s", lineNumber, columnNumber, m);
+ }
+
+ m_lastErrorLine = lineNumber;
+ m_lastErrorColumn = columnNumber;
+ ++m_errorCount;
+ }
+
+ if (type != warning)
+ m_sawError = true;
+
+ if (type == fatal)
+ stopParsing();
+}
+
+bool XMLTokenizer::enterText()
+{
+#ifndef USE_QXMLSTREAM
+ ASSERT(m_bufferedText.size() == 0);
+#endif
+ RefPtr<Node> newNode = new Text(m_doc, "");
+ if (!m_currentNode->addChild(newNode.get()))
+ return false;
+ setCurrentNode(newNode.get());
+ return true;
+}
+
+void XMLTokenizer::exitText()
+{
+ if (m_parserStopped)
+ return;
+
+ if (!m_currentNode || !m_currentNode->isTextNode())
+ return;
+
+#ifndef USE_QXMLSTREAM
+ ExceptionCode ec = 0;
+ static_cast<Text*>(m_currentNode)->appendData(toString(m_bufferedText.data(), m_bufferedText.size()), ec);
+ Vector<xmlChar> empty;
+ m_bufferedText.swap(empty);
+#endif
+
+ if (m_view && m_currentNode && !m_currentNode->attached())
+ m_currentNode->attach();
+
+ // FIXME: What's the right thing to do if the parent is really 0?
+ // Just leaving the current node set to the text node doesn't make much sense.
+ if (Node* par = m_currentNode->parentNode())
+ setCurrentNode(par);
+}
+
+void XMLTokenizer::initializeParserContext()
+{
+#ifndef USE_QXMLSTREAM
+ xmlSAXHandler sax;
+ memset(&sax, 0, sizeof(sax));
+ sax.error = normalErrorHandler;
+ sax.fatalError = fatalErrorHandler;
+ sax.characters = charactersHandler;
+ sax.processingInstruction = processingInstructionHandler;
+ sax.cdataBlock = cdataBlockHandler;
+ sax.comment = commentHandler;
+ sax.warning = warningHandler;
+ sax.startElementNs = startElementNsHandler;
+ sax.endElementNs = endElementNsHandler;
+ sax.getEntity = getEntityHandler;
+ sax.startDocument = startDocumentHandler;
+ sax.endDocument = endDocumentHandler;
+ sax.internalSubset = internalSubsetHandler;
+ sax.externalSubset = externalSubsetHandler;
+ sax.ignorableWhitespace = ignorableWhitespaceHandler;
+ sax.entityDecl = xmlSAX2EntityDecl;
+ sax.initialized = XML_SAX2_MAGIC;
+#endif
+ m_parserStopped = false;
+ m_sawError = false;
+ m_sawXSLTransform = false;
+ m_sawFirstElement = false;
+
+#ifndef USE_QXMLSTREAM
+ m_context = createStringParser(&sax, this);
+#endif
+}
+
+void XMLTokenizer::end()
+{
+#if ENABLE(XSLT)
+ if (m_sawXSLTransform) {
+ m_doc->setTransformSource(xmlDocPtrForString(m_doc->docLoader(), m_originalSourceForTransform, m_doc->url().string()));
+
+ m_doc->setParsing(false); // Make the doc think it's done, so it will apply xsl sheets.
+ m_doc->updateStyleSelector();
+ m_doc->setParsing(true);
+ m_parserStopped = true;
+ }
+#endif
+
+#ifndef USE_QXMLSTREAM
+ if (m_context) {
+ // Tell libxml we're done.
+ xmlParseChunk(m_context, 0, 0, 1);
+
+ if (m_context->myDoc)
+ xmlFreeDoc(m_context->myDoc);
+ xmlFreeParserCtxt(m_context);
+ m_context = 0;
+ }
+#else
+ if (m_stream.error() == QXmlStreamReader::PrematureEndOfDocumentError || (m_wroteText && !m_sawFirstElement)) {
+ handleError(fatal, qPrintable(m_stream.errorString()), lineNumber(),
+ columnNumber());
+ }
+#endif
+
+ if (m_sawError)
+ insertErrorMessageBlock();
+ else {
+ exitText();
+ m_doc->updateStyleSelector();
+ }
+
+ setCurrentNode(0);
+ if (!m_parsingFragment)
+ m_doc->finishedParsing();
+}
+
+void XMLTokenizer::finish()
+{
+ if (m_parserPaused)
+ m_finishCalled = true;
+ else
+ end();
+}
+
+static inline RefPtr<Element> createXHTMLParserErrorHeader(Document* doc, const String& errorMessages)
+{
+ ExceptionCode ec = 0;
+ RefPtr<Element> reportElement = doc->createElementNS(xhtmlNamespaceURI, "parsererror", ec);
+ reportElement->setAttribute(styleAttr, "display: block; white-space: pre; border: 2px solid #c77; padding: 0 1em 0 1em; margin: 1em; background-color: #fdd; color: black");
+
+ RefPtr<Element> h3 = doc->createElementNS(xhtmlNamespaceURI, "h3", ec);
+ reportElement->appendChild(h3.get(), ec);
+ h3->appendChild(doc->createTextNode("This page contains the following errors:"), ec);
+
+ RefPtr<Element> fixed = doc->createElementNS(xhtmlNamespaceURI, "div", ec);
+ reportElement->appendChild(fixed.get(), ec);
+ fixed->setAttribute(styleAttr, "font-family:monospace;font-size:12px");
+ fixed->appendChild(doc->createTextNode(errorMessages), ec);
+
+ h3 = doc->createElementNS(xhtmlNamespaceURI, "h3", ec);
+ reportElement->appendChild(h3.get(), ec);
+ h3->appendChild(doc->createTextNode("Below is a rendering of the page up to the first error."), ec);
+
+ return reportElement;
+}
+
+void XMLTokenizer::insertErrorMessageBlock()
+{
+#ifdef USE_QXMLSTREAM
+ if (m_parsingFragment)
+ return;
+#endif
+ // One or more errors occurred during parsing of the code. Display an error block to the user above
+ // the normal content (the DOM tree is created manually and includes line/col info regarding
+ // where the errors are located)
+
+ // Create elements for display
+ ExceptionCode ec = 0;
+ Document* doc = m_doc;
+ Node* documentElement = doc->documentElement();
+ if (!documentElement) {
+ RefPtr<Node> rootElement = doc->createElementNS(xhtmlNamespaceURI, "html", ec);
+ doc->appendChild(rootElement, ec);
+ RefPtr<Node> body = doc->createElementNS(xhtmlNamespaceURI, "body", ec);
+ rootElement->appendChild(body, ec);
+ documentElement = body.get();
+ }
+#if ENABLE(SVG)
+ else if (documentElement->namespaceURI() == SVGNames::svgNamespaceURI) {
+ // Until our SVG implementation has text support, it is best if we
+ // wrap the erroneous SVG document in an xhtml document and render
+ // the combined document with error messages.
+ RefPtr<Node> rootElement = doc->createElementNS(xhtmlNamespaceURI, "html", ec);
+ RefPtr<Node> body = doc->createElementNS(xhtmlNamespaceURI, "body", ec);
+ rootElement->appendChild(body, ec);
+ body->appendChild(documentElement, ec);
+ doc->appendChild(rootElement.get(), ec);
+ documentElement = body.get();
+ }
+#endif
+
+ RefPtr<Element> reportElement = createXHTMLParserErrorHeader(doc, m_errorMessages);
+ documentElement->insertBefore(reportElement, documentElement->firstChild(), ec);
+#if ENABLE(XSLT)
+ if (doc->transformSourceDocument()) {
+ RefPtr<Element> par = doc->createElementNS(xhtmlNamespaceURI, "p", ec);
+ reportElement->appendChild(par, ec);
+ par->setAttribute(styleAttr, "white-space: normal");
+ par->appendChild(doc->createTextNode("This document was created as the result of an XSL transformation. The line and column numbers given are from the transformed result."), ec);
+ }
+#endif
+ doc->updateRendering();
+}
+
+void XMLTokenizer::notifyFinished(CachedResource* finishedObj)
+{
+ ASSERT(m_pendingScript == finishedObj);
+ ASSERT(m_pendingScript->accessCount() > 0);
+
+ String cachedScriptUrl = m_pendingScript->url();
+ String scriptSource = m_pendingScript->script();
+ bool errorOccurred = m_pendingScript->errorOccurred();
+ m_pendingScript->deref(this);
+ m_pendingScript = 0;
+
+ RefPtr<Element> e = m_scriptElement;
+ m_scriptElement = 0;
+
+ if (errorOccurred)
+ EventTargetNodeCast(e.get())->dispatchHTMLEvent(errorEvent, true, false);
+ else {
+ m_view->frame()->loader()->executeScript(cachedScriptUrl, 0, scriptSource);
+ EventTargetNodeCast(e.get())->dispatchHTMLEvent(loadEvent, false, false);
+ }
+
+ m_scriptElement = 0;
+
+ if (!m_requestingScript)
+ resumeParsing();
+}
+
+bool XMLTokenizer::isWaitingForScripts() const
+{
+ return m_pendingScript != 0;
+}
+
+#if ENABLE(XSLT)
+void* xmlDocPtrForString(DocLoader* docLoader, const String& source, const String& url)
+{
+ if (source.isEmpty())
+ return 0;
+
+ // Parse in a single chunk into an xmlDocPtr
+ // FIXME: Hook up error handlers so that a failure to parse the main document results in
+ // good error messages.
+ const UChar BOM = 0xFEFF;
+ const unsigned char BOMHighByte = *reinterpret_cast<const unsigned char*>(&BOM);
+
+ xmlGenericErrorFunc oldErrorFunc = xmlGenericError;
+ void* oldErrorContext = xmlGenericErrorContext;
+
+ setLoaderForLibXMLCallbacks(docLoader);
+ xmlSetGenericErrorFunc(0, errorFunc);
+
+ xmlDocPtr sourceDoc = xmlReadMemory(reinterpret_cast<const char*>(source.characters()),
+ source.length() * sizeof(UChar),
+ url.latin1().data(),
+ BOMHighByte == 0xFF ? "UTF-16LE" : "UTF-16BE",
+ XSLT_PARSE_OPTIONS);
+
+ setLoaderForLibXMLCallbacks(0);
+ xmlSetGenericErrorFunc(oldErrorContext, oldErrorFunc);
+
+ return sourceDoc;
+}
+#endif
+
+int XMLTokenizer::lineNumber() const
+{
+#ifndef USE_QXMLSTREAM
+ return m_context ? m_context->input->line : 1;
+#else
+ return m_stream.lineNumber();
+#endif
+}
+
+int XMLTokenizer::columnNumber() const
+{
+#ifndef USE_QXMLSTREAM
+ return m_context ? m_context->input->col : 1;
+#else
+ return m_stream.columnNumber();
+#endif
+}
+
+void XMLTokenizer::stopParsing()
+{
+ Tokenizer::stopParsing();
+#ifndef USE_QXMLSTREAM
+ xmlStopParser(m_context);
+#endif
+}
+
+void XMLTokenizer::pauseParsing()
+{
+ if (m_parsingFragment)
+ return;
+
+ m_parserPaused = true;
+}
+
+void XMLTokenizer::resumeParsing()
+{
+ ASSERT(m_parserPaused);
+
+ m_parserPaused = false;
+
+ // First, execute any pending callbacks
+#ifndef USE_QXMLSTREAM
+ while (!m_pendingCallbacks->isEmpty()) {
+ m_pendingCallbacks->callAndRemoveFirstCallback(this);
+
+ // A callback paused the parser
+ if (m_parserPaused)
+ return;
+ }
+#else
+ parse();
+ if (m_parserPaused)
+ return;
+#endif
+
+ // Then, write any pending data
+ SegmentedString rest = m_pendingSrc;
+ m_pendingSrc.clear();
+ write(rest, false);
+
+ // Finally, if finish() has been called and write() didn't result
+ // in any further callbacks being queued, call end()
+ if (m_finishCalled
+#ifndef USE_QXMLSTREAM
+ && m_pendingCallbacks->isEmpty())
+#else
+ )
+#endif
+ end();
+}
+
+#ifndef USE_QXMLSTREAM
+static void balancedStartElementNsHandler(void* closure, const xmlChar* localname, const xmlChar* prefix,
+ const xmlChar* uri, int nb_namespaces, const xmlChar** namespaces,
+ int nb_attributes, int nb_defaulted, const xmlChar** libxmlAttributes)
+{
+ static_cast<XMLTokenizer*>(closure)->startElementNs(localname, prefix, uri, nb_namespaces, namespaces, nb_attributes, nb_defaulted, libxmlAttributes);
+}
+
+static void balancedEndElementNsHandler(void* closure, const xmlChar* localname, const xmlChar* prefix, const xmlChar* uri)
+{
+ static_cast<XMLTokenizer*>(closure)->endElementNs();
+}
+
+static void balancedCharactersHandler(void* closure, const xmlChar* s, int len)
+{
+ static_cast<XMLTokenizer*>(closure)->characters(s, len);
+}
+
+static void balancedProcessingInstructionHandler(void* closure, const xmlChar* target, const xmlChar* data)
+{
+ static_cast<XMLTokenizer*>(closure)->processingInstruction(target, data);
+}
+
+static void balancedCdataBlockHandler(void* closure, const xmlChar* s, int len)
+{
+ static_cast<XMLTokenizer*>(closure)->cdataBlock(s, len);
+}
+
+static void balancedCommentHandler(void* closure, const xmlChar* comment)
+{
+ static_cast<XMLTokenizer*>(closure)->comment(comment);
+}
+
+WTF_ATTRIBUTE_PRINTF(2, 3)
+static void balancedWarningHandler(void* closure, const char* message, ...)
+{
+ va_list args;
+ va_start(args, message);
+ static_cast<XMLTokenizer*>(closure)->error(XMLTokenizer::warning, message, args);
+ va_end(args);
+}
+#endif
+bool parseXMLDocumentFragment(const String& string, DocumentFragment* fragment, Element* parent)
+{
+ if (!string.length())
+ return true;
+
+ XMLTokenizer tokenizer(fragment, parent);
+
+#ifndef USE_QXMLSTREAM
+ xmlSAXHandler sax;
+ memset(&sax, 0, sizeof(sax));
+
+ sax.characters = balancedCharactersHandler;
+ sax.processingInstruction = balancedProcessingInstructionHandler;
+ sax.startElementNs = balancedStartElementNsHandler;
+ sax.endElementNs = balancedEndElementNsHandler;
+ sax.cdataBlock = balancedCdataBlockHandler;
+ sax.ignorableWhitespace = balancedCharactersHandler;
+ sax.comment = balancedCommentHandler;
+ sax.warning = balancedWarningHandler;
+ sax.initialized = XML_SAX2_MAGIC;
+
+ int result = xmlParseBalancedChunkMemory(0, &sax, &tokenizer, 0, (const xmlChar*)string.utf8().data(), 0);
+ tokenizer.endDocument();
+ return result == 0;
+#else
+ tokenizer.write(String("<qxmlstreamdummyelement>"), false);
+ tokenizer.write(string, false);
+ tokenizer.write(String("</qxmlstreamdummyelement>"), false);
+ tokenizer.finish();
+ return !tokenizer.hasError();
+#endif
+}
+
+// --------------------------------
+
+struct AttributeParseState {
+ HashMap<String, String> attributes;
+ bool gotAttributes;
+};
+
+#ifndef USE_QXMLSTREAM
+static void attributesStartElementNsHandler(void* closure, const xmlChar* xmlLocalName, const xmlChar* xmlPrefix,
+ const xmlChar* xmlURI, int nb_namespaces, const xmlChar** namespaces,
+ int nb_attributes, int nb_defaulted, const xmlChar** libxmlAttributes)
+{
+ if (strcmp(reinterpret_cast<const char*>(xmlLocalName), "attrs") != 0)
+ return;
+
+ xmlParserCtxtPtr ctxt = static_cast<xmlParserCtxtPtr>(closure);
+ AttributeParseState* state = static_cast<AttributeParseState*>(ctxt->_private);
+
+ state->gotAttributes = true;
+
+ xmlSAX2Attributes* attributes = reinterpret_cast<xmlSAX2Attributes*>(libxmlAttributes);
+ for(int i = 0; i < nb_attributes; i++) {
+ String attrLocalName = toString(attributes[i].localname);
+ int valueLength = (int) (attributes[i].end - attributes[i].value);
+ String attrValue = toString(attributes[i].value, valueLength);
+ String attrPrefix = toString(attributes[i].prefix);
+ String attrQName = attrPrefix.isEmpty() ? attrLocalName : attrPrefix + ":" + attrLocalName;
+
+ state->attributes.set(attrQName, attrValue);
+ }
+}
+#else
+static void attributesStartElementNsHandler(AttributeParseState* state, const QXmlStreamAttributes& attrs)
+{
+ if (attrs.count() <= 0)
+ return;
+
+ state->gotAttributes = true;
+
+ for(int i = 0; i < attrs.count(); i++) {
+ const QXmlStreamAttribute& attr = attrs[i];
+ String attrLocalName = attr.name();
+ String attrValue = attr.value();
+ String attrURI = attr.namespaceUri();
+ String attrQName = attr.qualifiedName();
+ state->attributes.set(attrQName, attrValue);
+ }
+}
+#endif
+
+HashMap<String, String> parseAttributes(const String& string, bool& attrsOK)
+{
+ AttributeParseState state;
+ state.gotAttributes = false;
+
+#ifndef USE_QXMLSTREAM
+ xmlSAXHandler sax;
+ memset(&sax, 0, sizeof(sax));
+ sax.startElementNs = attributesStartElementNsHandler;
+ sax.initialized = XML_SAX2_MAGIC;
+ xmlParserCtxtPtr parser = createStringParser(&sax, &state);
+ String parseString = "<?xml version=\"1.0\"?><attrs " + string + " />";
+ xmlParseChunk(parser, reinterpret_cast<const char*>(parseString.characters()), parseString.length() * sizeof(UChar), 1);
+ if (parser->myDoc)
+ xmlFreeDoc(parser->myDoc);
+ xmlFreeParserCtxt(parser);
+#else
+ QXmlStreamReader stream;
+ QString dummy = QString("<?xml version=\"1.0\"?><attrs %1 />").arg(string);
+ stream.addData(dummy);
+ while (!stream.atEnd()) {
+ stream.readNext();
+ if (stream.isStartElement()) {
+ attributesStartElementNsHandler(&state, stream.attributes());
+ }
+ }
+#endif
+ attrsOK = state.gotAttributes;
+ return state.attributes;
+}
+
+#ifdef USE_QXMLSTREAM
+static inline String prefixFromQName(const QString& qName)
+{
+ const int offset = qName.indexOf(QLatin1Char(':'));
+ if (offset <= 0)
+ return String();
+ else
+ return qName.left(offset);
+}
+
+static inline void handleElementNamespaces(Element* newElement, const QXmlStreamNamespaceDeclarations &ns,
+ ExceptionCode& ec)
+{
+ for (int i = 0; i < ns.count(); ++i) {
+ const QXmlStreamNamespaceDeclaration &decl = ns[i];
+ String namespaceURI = decl.namespaceUri();
+ String namespaceQName = decl.prefix().isEmpty() ? String("xmlns") : String("xmlns:") + decl.prefix();
+ newElement->setAttributeNS("http://www.w3.org/2000/xmlns/", namespaceQName, namespaceURI, ec);
+ if (ec) // exception setting attributes
+ return;
+ }
+}
+
+static inline void handleElementAttributes(Element* newElement, const QXmlStreamAttributes &attrs, ExceptionCode& ec)
+{
+ for (int i = 0; i < attrs.count(); ++i) {
+ const QXmlStreamAttribute &attr = attrs[i];
+ String attrLocalName = attr.name();
+ String attrValue = attr.value();
+ String attrURI = attr.namespaceUri().isEmpty() ? String() : String(attr.namespaceUri());
+ String attrQName = attr.qualifiedName();
+ newElement->setAttributeNS(attrURI, attrQName, attrValue, ec);
+ if (ec) // exception setting attributes
+ return;
+ }
+}
+
+void XMLTokenizer::parse()
+{
+ while (!m_parserStopped && !m_parserPaused && !m_stream.atEnd()) {
+ m_stream.readNext();
+ switch (m_stream.tokenType()) {
+ case QXmlStreamReader::StartDocument: {
+ startDocument();
+ }
+ break;
+ case QXmlStreamReader::EndDocument: {
+ endDocument();
+ }
+ break;
+ case QXmlStreamReader::StartElement: {
+ parseStartElement();
+ }
+ break;
+ case QXmlStreamReader::EndElement: {
+ parseEndElement();
+ }
+ break;
+ case QXmlStreamReader::Characters: {
+ if (m_stream.isCDATA()) {
+ //cdata
+ parseCdata();
+ } else {
+ //characters
+ parseCharacters();
+ }
+ }
+ break;
+ case QXmlStreamReader::Comment: {
+ parseComment();
+ }
+ break;
+ case QXmlStreamReader::DTD: {
+ //qDebug()<<"------------- DTD";
+ parseDtd();
+ }
+ break;
+ case QXmlStreamReader::EntityReference: {
+ //qDebug()<<"---------- ENTITY = "<<m_stream.name().toString()
+ // <<", t = "<<m_stream.text().toString();
+ if (isXHTMLDocument()) {
+ QString entity = m_stream.name().toString();
+ UChar c = decodeNamedEntity(entity.toUtf8().constData());
+ if (m_currentNode->isTextNode() || enterText()) {
+ ExceptionCode ec = 0;
+ String str(&c, 1);
+ //qDebug()<<" ------- adding entity "<<str;
+ static_cast<Text*>(m_currentNode)->appendData(str, ec);
+ }
+ }
+ }
+ break;
+ case QXmlStreamReader::ProcessingInstruction: {
+ parseProcessingInstruction();
+ }
+ break;
+ default: {
+ if (m_stream.error() != QXmlStreamReader::PrematureEndOfDocumentError) {
+ ErrorType type = (m_stream.error() == QXmlStreamReader::NotWellFormedError) ?
+ fatal : warning;
+ handleError(type, qPrintable(m_stream.errorString()), lineNumber(),
+ columnNumber());
+ }
+ }
+ break;
+ }
+ }
+}
+
+void XMLTokenizer::startDocument()
+{
+ initializeParserContext();
+ ExceptionCode ec = 0;
+
+ if (!m_parsingFragment) {
+ m_doc->setXMLStandalone(m_stream.isStandaloneDocument(), ec);
+
+#if QT_VERSION >= 0x040400
+ QStringRef version = m_stream.documentVersion();
+ if (!version.isEmpty())
+ m_doc->setXMLVersion(version, ec);
+ QStringRef encoding = m_stream.documentEncoding();
+ if (!encoding.isEmpty())
+ m_doc->setXMLEncoding(encoding);
+#endif
+ }
+}
+
+void XMLTokenizer::parseStartElement()
+{
+ if (!m_sawFirstElement && m_parsingFragment) {
+ // skip dummy element for fragments
+ m_sawFirstElement = true;
+ return;
+ }
+ m_sawFirstElement = true;
+
+ exitText();
+
+ String localName = m_stream.name();
+ String uri = m_stream.namespaceUri();
+ String prefix = prefixFromQName(m_stream.qualifiedName().toString());
+
+ if (m_parsingFragment && uri.isNull()) {
+ Q_ASSERT (prefix.isNull());
+ uri = m_defaultNamespaceURI;
+ }
+
+ ExceptionCode ec = 0;
+ QualifiedName qName(prefix, localName, uri);
+ RefPtr<Element> newElement = m_doc->createElement(qName, true, ec);
+ if (!newElement) {
+ stopParsing();
+ return;
+ }
+
+ handleElementNamespaces(newElement.get(), m_stream.namespaceDeclarations(), ec);
+ if (ec) {
+ stopParsing();
+ return;
+ }
+
+ handleElementAttributes(newElement.get(), m_stream.attributes(), ec);
+ if (ec) {
+ stopParsing();
+ return;
+ }
+
+ if (newElement->hasTagName(scriptTag))
+ static_cast<HTMLScriptElement*>(newElement.get())->setCreatedByParser(true);
+
+ if (newElement->hasTagName(HTMLNames::scriptTag)
+#if ENABLE(SVG)
+ || newElement->hasTagName(SVGNames::scriptTag)
+#endif
+ )
+ m_scriptStartLine = lineNumber();
+
+ if (!m_currentNode->addChild(newElement.get())) {
+ stopParsing();
+ return;
+ }
+
+ setCurrentNode(newElement.get());
+ if (m_view && !newElement->attached())
+ newElement->attach();
+}
+
+void XMLTokenizer::parseEndElement()
+{
+ exitText();
+
+ Node* n = m_currentNode;
+
+ // skip end of dummy element
+// if (m_parsingFragment & n->nodeType() == Node::DOCUMENT_FRAGMENT_NODE)
+// return;
+
+ RefPtr<Node> parent = n->parentNode();
+ n->finishParsingChildren();
+
+ // don't load external scripts for standalone documents (for now)
+ if (n->isElementNode() && m_view && (static_cast<Element*>(n)->hasTagName(scriptTag)
+#if ENABLE(SVG)
+ || static_cast<Element*>(n)->hasTagName(SVGNames::scriptTag)
+#endif
+ )) {
+
+
+ ASSERT(!m_pendingScript);
+
+ m_requestingScript = true;
+
+ Element* scriptElement = static_cast<Element*>(n);
+ String scriptHref;
+
+ if (static_cast<Element*>(n)->hasTagName(scriptTag))
+ scriptHref = scriptElement->getAttribute(srcAttr);
+#if ENABLE(SVG)
+ else if (static_cast<Element*>(n)->hasTagName(SVGNames::scriptTag))
+ scriptHref = scriptElement->getAttribute(XLinkNames::hrefAttr);
+#endif
+ if (!scriptHref.isEmpty()) {
+ // we have a src attribute
+ const AtomicString& charset = scriptElement->getAttribute(charsetAttr);
+ if ((m_pendingScript = m_doc->docLoader()->requestScript(scriptHref, charset))) {
+ m_scriptElement = scriptElement;
+ m_pendingScript->ref(this);
+
+ // m_pendingScript will be 0 if script was already loaded and ref() executed it
+ if (m_pendingScript)
+ pauseParsing();
+ } else
+ m_scriptElement = 0;
+
+ } else {
+ String scriptCode = "";
+ for (Node* child = scriptElement->firstChild(); child; child = child->nextSibling()) {
+ if (child->isTextNode() || child->nodeType() == Node::CDATA_SECTION_NODE)
+ scriptCode += static_cast<CharacterData*>(child)->data();
+ }
+ m_view->frame()->loader()->executeScript(m_doc->url().string(), m_scriptStartLine - 1, scriptCode);
+ }
+ m_requestingScript = false;
+ }
+
+ setCurrentNode(parent.get());
+}
+
+void XMLTokenizer::parseCharacters()
+{
+ if (m_currentNode->isTextNode() || enterText()) {
+ ExceptionCode ec = 0;
+ static_cast<Text*>(m_currentNode)->appendData(m_stream.text(), ec);
+ }
+}
+
+void XMLTokenizer::parseProcessingInstruction()
+{
+ exitText();
+
+ // ### handle exceptions
+ int exception = 0;
+ RefPtr<ProcessingInstruction> pi = m_doc->createProcessingInstruction(
+ m_stream.processingInstructionTarget(),
+ m_stream.processingInstructionData(), exception);
+ if (exception)
+ return;
+
+ if (!m_currentNode->addChild(pi.get()))
+ return;
+ if (m_view && !pi->attached())
+ pi->attach();
+
+ // don't load stylesheets for standalone documents
+ if (m_doc->frame()) {
+ m_sawXSLTransform = !m_sawFirstElement && !pi->checkStyleSheet();
+ if (m_sawXSLTransform)
+ stopParsing();
+ }
+}
+
+void XMLTokenizer::parseCdata()
+{
+ exitText();
+
+ RefPtr<Node> newNode = new CDATASection(m_doc, m_stream.text());
+ if (!m_currentNode->addChild(newNode.get()))
+ return;
+ if (m_view && !newNode->attached())
+ newNode->attach();
+}
+
+void XMLTokenizer::parseComment()
+{
+ exitText();
+
+ RefPtr<Node> newNode = new Comment(m_doc, m_stream.text());
+ m_currentNode->addChild(newNode.get());
+ if (m_view && !newNode->attached())
+ newNode->attach();
+}
+
+void XMLTokenizer::endDocument()
+{
+}
+
+bool XMLTokenizer::hasError() const
+{
+ return m_stream.hasError();
+}
+
+#if QT_VERSION < 0x040400
+static QString parseId(const QString &dtd, int *pos, bool *ok)
+{
+ *ok = true;
+ int start = *pos + 1;
+ int end = start;
+ if (dtd.at(*pos) == QLatin1Char('\''))
+ while (start < dtd.length() && dtd.at(end) != QLatin1Char('\''))
+ ++end;
+ else if (dtd.at(*pos) == QLatin1Char('\"'))
+ while (start < dtd.length() && dtd.at(end) != QLatin1Char('\"'))
+ ++end;
+ else {
+ *ok = false;
+ return QString();
+ }
+ *pos = end + 1;
+ return dtd.mid(start, end - start);
+}
+#endif
+
+void XMLTokenizer::parseDtd()
+{
+#if QT_VERSION >= 0x040400
+ QStringRef name = m_stream.dtdName();
+ QStringRef publicId = m_stream.dtdPublicId();
+ QStringRef systemId = m_stream.dtdSystemId();
+#else
+ QString dtd = m_stream.text().toString();
+
+ int start = dtd.indexOf("<!DOCTYPE ") + 10;
+ while (start < dtd.length() && dtd.at(start).isSpace())
+ ++start;
+ int end = start;
+ while (start < dtd.length() && !dtd.at(end).isSpace())
+ ++end;
+ QString name = dtd.mid(start, end - start);
+
+ start = end;
+ while (start < dtd.length() && dtd.at(start).isSpace())
+ ++start;
+ end = start;
+ while (start < dtd.length() && !dtd.at(end).isSpace())
+ ++end;
+ QString id = dtd.mid(start, end - start);
+ start = end;
+ while (start < dtd.length() && dtd.at(start).isSpace())
+ ++start;
+ QString publicId;
+ QString systemId;
+ if (id == QLatin1String("PUBLIC")) {
+ bool ok;
+ publicId = parseId(dtd, &start, &ok);
+ if (!ok) {
+ handleError(fatal, "Invalid DOCTYPE", lineNumber(), columnNumber());
+ return;
+ }
+ while (start < dtd.length() && dtd.at(start).isSpace())
+ ++start;
+ systemId = parseId(dtd, &start, &ok);
+ if (!ok) {
+ handleError(fatal, "Invalid DOCTYPE", lineNumber(), columnNumber());
+ return;
+ }
+ } else if (id == QLatin1String("SYSTEM")) {
+ bool ok;
+ systemId = parseId(dtd, &start, &ok);
+ if (!ok) {
+ handleError(fatal, "Invalid DOCTYPE", lineNumber(), columnNumber());
+ return;
+ }
+ } else if (id == QLatin1String("[") || id == QLatin1String(">")) {
+ } else {
+ handleError(fatal, "Invalid DOCTYPE", lineNumber(), columnNumber());
+ return;
+ }
+#endif
+
+ //qDebug() << dtd << name << publicId << systemId;
+ if ((publicId == "-//W3C//DTD XHTML 1.0 Transitional//EN")
+ || (publicId == "-//W3C//DTD XHTML 1.1//EN")
+ || (publicId == "-//W3C//DTD XHTML 1.0 Strict//EN")
+ || (publicId == "-//W3C//DTD XHTML 1.0 Frameset//EN")
+ || (publicId == "-//W3C//DTD XHTML Basic 1.0//EN")
+ || (publicId == "-//W3C//DTD XHTML 1.1 plus MathML 2.0//EN")
+ || (publicId == "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN")
+ || (publicId == "-//WAPFORUM//DTD XHTML Mobile 1.0//EN")) {
+ setIsXHTMLDocument(true); // controls if we replace entities or not.
+ }
+ if (!m_parsingFragment)
+ m_doc->addChild(new DocumentType(m_doc, name, publicId, systemId));
+
+}
+#endif
+}
+
+
diff --git a/WebCore/dom/XMLTokenizer.h b/WebCore/dom/XMLTokenizer.h
new file mode 100644
index 0000000..e754e84
--- /dev/null
+++ b/WebCore/dom/XMLTokenizer.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2000 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Samuel Weinig (sam@webkit.org)
+ * Copyright (C) 2007 Trolltech ASA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef XMLTokenizer_h
+#define XMLTokenizer_h
+
+#include "CachedResourceClient.h"
+#include "SegmentedString.h"
+#include "StringHash.h"
+#include "Tokenizer.h"
+#include <wtf/HashMap.h>
+#include <wtf/OwnPtr.h>
+
+#if PLATFORM(QT)
+#if !ENABLE(XSLT)
+#define USE_QXMLSTREAM
+#endif
+#endif
+
+#ifndef USE_QXMLSTREAM
+#include <libxml/tree.h>
+#include <libxml/xmlstring.h>
+#else
+#include <QtXml/qxmlstream.h>
+#endif
+
+namespace WebCore {
+
+ class Node;
+ class CachedScript;
+ class DocLoader;
+ class DocumentFragment;
+ class Document;
+ class Element;
+ class FrameView;
+ class PendingCallbacks;
+
+ class XMLTokenizer : public Tokenizer, public CachedResourceClient {
+ public:
+ XMLTokenizer(Document*, FrameView* = 0);
+ XMLTokenizer(DocumentFragment*, Element*);
+ ~XMLTokenizer();
+
+ enum ErrorType { warning, nonFatal, fatal };
+
+ // from Tokenizer
+ virtual bool write(const SegmentedString&, bool appendData);
+ virtual void finish();
+ virtual bool isWaitingForScripts() const;
+ virtual void stopParsing();
+
+ void end();
+
+ void pauseParsing();
+ void resumeParsing();
+
+ void setIsXHTMLDocument(bool isXHTML) { m_isXHTMLDocument = isXHTML; }
+ bool isXHTMLDocument() const { return m_isXHTMLDocument; }
+
+ // from CachedResourceClient
+ virtual void notifyFinished(CachedResource* finishedObj);
+
+#ifndef USE_QXMLSTREAM
+ // callbacks from parser SAX
+ void error(ErrorType, const char* message, va_list args) WTF_ATTRIBUTE_PRINTF(3, 0);
+ void startElementNs(const xmlChar* xmlLocalName, const xmlChar* xmlPrefix, const xmlChar* xmlURI, int nb_namespaces,
+ const xmlChar** namespaces, int nb_attributes, int nb_defaulted, const xmlChar** libxmlAttributes);
+ void endElementNs();
+ void characters(const xmlChar* s, int len);
+ void processingInstruction(const xmlChar* target, const xmlChar* data);
+ void cdataBlock(const xmlChar* s, int len);
+ void comment(const xmlChar* s);
+ void startDocument(const xmlChar* version, const xmlChar* encoding, int standalone);
+ void internalSubset(const xmlChar* name, const xmlChar* externalID, const xmlChar* systemID);
+ void endDocument();
+#else
+ void parse();
+ void startDocument();
+ void parseStartElement();
+ void parseEndElement();
+ void parseCharacters();
+ void parseProcessingInstruction();
+ void parseCdata();
+ void parseComment();
+ void endDocument();
+ void parseDtd();
+ bool hasError() const;
+#endif
+
+ void handleError(ErrorType type, const char* m, int lineNumber, int columnNumber);
+
+ virtual bool wellFormed() const { return !m_sawError; }
+
+ int lineNumber() const;
+ int columnNumber() const;
+
+ private:
+ void initializeParserContext();
+ void setCurrentNode(Node*);
+
+ void insertErrorMessageBlock();
+
+ bool enterText();
+ void exitText();
+
+ Document* m_doc;
+ FrameView* m_view;
+
+ String m_originalSourceForTransform;
+
+#ifdef USE_QXMLSTREAM
+ QXmlStreamReader m_stream;
+ bool m_wroteText;
+#else
+ xmlParserCtxtPtr m_context;
+#endif
+ Node* m_currentNode;
+ bool m_currentNodeIsReferenced;
+
+ bool m_sawError;
+ bool m_sawXSLTransform;
+ bool m_sawFirstElement;
+ bool m_isXHTMLDocument;
+
+ bool m_parserPaused;
+ bool m_requestingScript;
+ bool m_finishCalled;
+
+ int m_errorCount;
+ int m_lastErrorLine;
+ int m_lastErrorColumn;
+ String m_errorMessages;
+
+ CachedScript* m_pendingScript;
+ RefPtr<Element> m_scriptElement;
+ int m_scriptStartLine;
+
+ bool m_parsingFragment;
+ String m_defaultNamespaceURI;
+
+ typedef HashMap<String, String> PrefixForNamespaceMap;
+ PrefixForNamespaceMap m_prefixToNamespaceMap;
+#ifndef USE_QXMLSTREAM
+ OwnPtr<PendingCallbacks> m_pendingCallbacks;
+ Vector<xmlChar> m_bufferedText;
+#endif
+ SegmentedString m_pendingSrc;
+ };
+
+#if ENABLE(XSLT)
+void* xmlDocPtrForString(DocLoader*, const String& source, const String& url);
+void setLoaderForLibXMLCallbacks(DocLoader*);
+#endif
+
+HashMap<String, String> parseAttributes(const String&, bool& attrsOK);
+bool parseXMLDocumentFragment(const String&, DocumentFragment*, Element* parent = 0);
+
+} // namespace WebCore
+
+#endif // XMLTokenizer_h
diff --git a/WebCore/dom/make_names.pl b/WebCore/dom/make_names.pl
new file mode 100755
index 0000000..04d3683
--- /dev/null
+++ b/WebCore/dom/make_names.pl
@@ -0,0 +1,497 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005, 2006, 2007 Apple 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:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+
+use strict;
+use Getopt::Long;
+use File::Path;
+use Config;
+
+my $printFactory = 0;
+my $cppNamespace = "";
+my $namespace = "";
+my $namespacePrefix = "";
+my $namespaceURI = "";
+my $tagsFile = "";
+my $attrsFile = "";
+my $outputDir = ".";
+my @tags = ();
+my @attrs = ();
+my $tagsNullNamespace = 0;
+my $attrsNullNamespace = 0;
+my $extraDefines = 0;
+my $preprocessor = "/usr/bin/gcc -E -P -x c++";
+
+GetOptions('tags=s' => \$tagsFile,
+ 'attrs=s' => \$attrsFile,
+ 'outputDir=s' => \$outputDir,
+ 'namespace=s' => \$namespace,
+ 'namespacePrefix=s' => \$namespacePrefix,
+ 'namespaceURI=s' => \$namespaceURI,
+ 'cppNamespace=s' => \$cppNamespace,
+ 'factory' => \$printFactory,
+ 'tagsNullNamespace' => \$tagsNullNamespace,
+ 'attrsNullNamespace' => \$attrsNullNamespace,
+ 'extraDefines=s' => \$extraDefines,
+ 'preprocessor=s' => \$preprocessor);
+
+die "You must specify a namespace (e.g. SVG) for <namespace>Names.h" unless $namespace;
+die "You must specify a namespaceURI (e.g. http://www.w3.org/2000/svg)" unless $namespaceURI;
+die "You must specify a cppNamespace (e.g. DOM) used for <cppNamespace>::<namespace>Names::fooTag" unless $cppNamespace;
+die "You must specify at least one of --tags <file> or --attrs <file>" unless (length($tagsFile) || length($attrsFile));
+
+$namespacePrefix = $namespace unless $namespacePrefix;
+
+@tags = readNames($tagsFile) if length($tagsFile);
+@attrs = readNames($attrsFile) if length($attrsFile);
+
+mkpath($outputDir);
+my $namesBasePath = "$outputDir/${namespace}Names";
+my $factoryBasePath = "$outputDir/${namespace}ElementFactory";
+
+printNamesHeaderFile("$namesBasePath.h");
+printNamesCppFile("$namesBasePath.cpp");
+if ($printFactory) {
+ printFactoryCppFile("$factoryBasePath.cpp");
+ printFactoryHeaderFile("$factoryBasePath.h");
+}
+
+
+## Support routines
+
+sub readNames
+{
+ my $namesFile = shift;
+
+ if ($extraDefines eq 0) {
+ die "Failed to open file: $namesFile" unless open NAMES, $preprocessor . " " . $namesFile . "|" or die;
+ } else {
+ die "Failed to open file: $namesFile" unless open NAMES, $preprocessor . " -D" . join(" -D", split(" ", $extraDefines)) . " " . $namesFile . "|" or die;
+ }
+
+ my @names = ();
+ while (<NAMES>) {
+ next if (m/#/);
+ next if (m/^[ \t]*$/);
+ s/-/_/g;
+ chomp $_;
+ push @names, $_;
+ }
+ close(NAMES);
+
+ die "Failed to read names from file: $namesFile" unless (scalar(@names));
+
+ return @names
+}
+
+sub printMacros
+{
+ my ($F, $macro, $suffix, @names) = @_;
+ for my $name (@names) {
+ print F " $macro $name","$suffix;\n";
+ }
+}
+
+sub printConstructors
+{
+ my ($F, @names) = @_;
+ print F "#if ENABLE(SVG)\n";
+ for my $name (@names) {
+ my $upperCase = upperCaseName($name);
+
+ print F "${namespace}Element *${name}Constructor(Document *doc, bool createdByParser)\n";
+ print F "{\n";
+ print F " return new ${namespace}${upperCase}Element(${name}Tag, doc);\n";
+ print F "}\n\n";
+ }
+ print F "#endif\n";
+}
+
+sub printFunctionInits
+{
+ my ($F, @names) = @_;
+ for my $name (@names) {
+ print F " gFunctionMap->set(${name}Tag.localName().impl(), ${name}Constructor);\n";
+ }
+}
+
+sub svgCapitalizationHacks
+{
+ my $name = shift;
+
+ if ($name =~ /^fe(.+)$/) {
+ $name = "FE" . ucfirst $1;
+ }
+ $name =~ s/kern/Kern/;
+ $name =~ s/mpath/MPath/;
+ $name =~ s/svg/SVG/;
+ $name =~ s/tref/TRef/;
+ $name =~ s/tspan/TSpan/;
+
+ return $name;
+}
+
+sub upperCaseName
+{
+ my $name = shift;
+
+ $name = svgCapitalizationHacks($name) if ($namespace eq "SVG");
+
+ while ($name =~ /^(.*?)_(.*)/) {
+ $name = $1 . ucfirst $2;
+ }
+
+ return ucfirst $name;
+}
+
+sub printLicenseHeader
+{
+ my $F = shift;
+ print F "/*
+ * THIS FILE IS AUTOMATICALLY GENERATED, DO NOT EDIT.
+ *
+ *
+ * Copyright (C) 2005 Apple Computer, 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:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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.
+ */
+
+
+";
+}
+
+sub printNamesHeaderFile
+{
+ my ($headerPath) = shift;
+ my $F;
+ open F, ">$headerPath";
+
+ printLicenseHeader($F);
+ print F "#ifndef DOM_${namespace}NAMES_H\n";
+ print F "#define DOM_${namespace}NAMES_H\n\n";
+ print F "#include \"QualifiedName.h\"\n\n";
+
+ print F "namespace $cppNamespace { namespace ${namespace}Names {\n\n";
+
+ my $lowerNamespace = lc($namespacePrefix);
+ print F "#ifndef DOM_${namespace}NAMES_HIDE_GLOBALS\n";
+ print F "// Namespace\n";
+ print F "extern const WebCore::AtomicString ${lowerNamespace}NamespaceURI;\n\n";
+
+ if (scalar(@tags)) {
+ print F "// Tags\n";
+ printMacros($F, "extern const WebCore::QualifiedName", "Tag", @tags);
+ print F "\n\nWebCore::QualifiedName** get${namespace}Tags(size_t* size);\n";
+ }
+
+ if (scalar(@attrs)) {
+ print F "// Attributes\n";
+ printMacros($F, "extern const WebCore::QualifiedName", "Attr", @attrs);
+ print F "\n\nWebCore::QualifiedName** get${namespace}Attr(size_t* size);\n";
+ }
+ print F "#endif\n\n";
+ print F "void init();\n\n";
+ print F "} }\n\n";
+ print F "#endif\n\n";
+
+ close F;
+}
+
+sub printNamesCppFile
+{
+ my $cppPath = shift;
+ my $F;
+ open F, ">$cppPath";
+
+ printLicenseHeader($F);
+
+ my $lowerNamespace = lc($namespacePrefix);
+
+print F "#include \"config.h\"\n";
+
+print F "#ifdef AVOID_STATIC_CONSTRUCTORS\n";
+print F "#define DOM_${namespace}NAMES_HIDE_GLOBALS 1\n";
+print F "#else\n";
+print F "#define QNAME_DEFAULT_CONSTRUCTOR 1\n";
+print F "#endif\n\n";
+
+
+print F "#include \"${namespace}Names.h\"\n\n";
+print F "#include \"StaticConstructors.h\"\n";
+
+print F "namespace $cppNamespace { namespace ${namespace}Names {
+
+using namespace WebCore;
+
+DEFINE_GLOBAL(AtomicString, ${lowerNamespace}NamespaceURI, \"$namespaceURI\")
+";
+
+ if (scalar(@tags)) {
+ print F "// Tags\n";
+ for my $name (@tags) {
+ print F "DEFINE_GLOBAL(QualifiedName, ", $name, "Tag, nullAtom, \"$name\", ${lowerNamespace}NamespaceURI);\n";
+ }
+
+ print F "\n\nWebCore::QualifiedName** get${namespace}Tags(size_t* size)\n";
+ print F "{\n static WebCore::QualifiedName* ${namespace}Tags[] = {\n";
+ for my $name (@tags) {
+ print F " (WebCore::QualifiedName*)&${name}Tag,\n";
+ }
+ print F " };\n";
+ print F " *size = ", scalar(@tags), ";\n";
+ print F " return ${namespace}Tags;\n";
+ print F "}\n";
+
+ }
+
+ if (scalar(@attrs)) {
+ print F "\n// Attributes\n";
+ for my $name (@attrs) {
+ print F "DEFINE_GLOBAL(QualifiedName, ", $name, "Attr, nullAtom, \"$name\", ${lowerNamespace}NamespaceURI);\n";
+ }
+ print F "\n\nWebCore::QualifiedName** get${namespace}Attrs(size_t* size)\n";
+ print F "{\n static WebCore::QualifiedName* ${namespace}Attr[] = {\n";
+ for my $name (@attrs) {
+ print F " (WebCore::QualifiedName*)&${name}Attr,\n";
+ }
+ print F " };\n";
+ print F " *size = ", scalar(@attrs), ";\n";
+ print F " return ${namespace}Attr;\n";
+ print F "}\n";
+ }
+
+print F "\nvoid init()
+{
+ static bool initialized = false;
+ if (initialized)
+ return;
+ initialized = true;
+
+ // Use placement new to initialize the globals.
+
+ AtomicString::init();
+";
+
+ print(F " AtomicString ${lowerNamespace}NS(\"$namespaceURI\");\n\n");
+
+ print(F " // Namespace\n");
+ print(F " new ((void*)&${lowerNamespace}NamespaceURI) AtomicString(${lowerNamespace}NS);\n\n");
+ if (scalar(@tags)) {
+ my $tagsNamespace = $tagsNullNamespace ? "nullAtom" : "${lowerNamespace}NS";
+ printDefinitions($F, \@tags, "tags", $tagsNamespace);
+ }
+ if (scalar(@attrs)) {
+ my $attrsNamespace = $attrsNullNamespace ? "nullAtom" : "${lowerNamespace}NS";
+ printDefinitions($F, \@attrs, "attributes", $attrsNamespace);
+ }
+
+ print F "}\n\n} }\n\n";
+ close F;
+}
+
+sub printElementIncludes
+{
+ my ($F, @names) = @_;
+ for my $name (@names) {
+ my $upperCase = upperCaseName($name);
+ print F "#include \"${namespace}${upperCase}Element.h\"\n";
+ }
+}
+
+sub printDefinitions
+{
+ my ($F, $namesRef, $type, $namespaceURI) = @_;
+ my $singularType = substr($type, 0, -1);
+ my $shortType = substr($singularType, 0, 4);
+ my $shortCamelType = ucfirst($shortType);
+ my $shortUpperType = uc($shortType);
+
+ print F " // " . ucfirst($type) . "\n";
+
+ for my $name (@$namesRef) {
+ print F " const char *$name","${shortCamelType}String = \"$name\";\n";
+ }
+
+ for my $name (@$namesRef) {
+ if ($name =~ /_/) {
+ my $realName = $name;
+ $realName =~ s/_/-/g;
+ print F " ${name}${shortCamelType}String = \"$realName\";\n";
+ }
+ }
+ print F "\n";
+
+ for my $name (@$namesRef) {
+ print F " new ((void*)&$name","${shortCamelType}) QualifiedName(nullAtom, $name","${shortCamelType}String, $namespaceURI);\n";
+ }
+
+}
+
+sub printFactoryCppFile
+{
+ my $cppPath = shift;
+ my $F;
+ open F, ">$cppPath";
+
+printLicenseHeader($F);
+
+print F <<END
+#include "config.h"
+#include "${namespace}ElementFactory.h"
+#include "${namespace}Names.h"
+#include "Page.h"
+#include "Settings.h"
+END
+;
+
+printElementIncludes($F, @tags);
+
+print F <<END
+#include <wtf/HashMap.h>
+
+using namespace WebCore;
+using namespace ${cppNamespace}::${namespace}Names;
+
+typedef ${namespace}Element *(*ConstructorFunc)(Document *doc, bool createdByParser);
+typedef WTF::HashMap<AtomicStringImpl*, ConstructorFunc> FunctionMap;
+
+static FunctionMap *gFunctionMap = 0;
+
+namespace ${cppNamespace} {
+
+END
+;
+
+printConstructors($F, @tags);
+
+print F <<END
+#if ENABLE(SVG)
+static inline void createFunctionMapIfNecessary()
+{
+ if (gFunctionMap)
+ return;
+ // Create the table.
+ gFunctionMap = new FunctionMap;
+
+ // Populate it with constructor functions.
+END
+;
+
+printFunctionInits($F, @tags);
+
+print F <<END
+}
+#endif
+
+${namespace}Element *${namespace}ElementFactory::create${namespace}Element(const QualifiedName& qName, Document* doc, bool createdByParser)
+{
+#if ENABLE(SVG)
+ // Don't make elements without a document
+ if (!doc)
+ return 0;
+
+ Settings* settings = doc->settings();
+ if (settings && settings->usesDashboardBackwardCompatibilityMode())
+ return 0;
+
+ createFunctionMapIfNecessary();
+ ConstructorFunc func = gFunctionMap->get(qName.localName().impl());
+ if (func)
+ return func(doc, createdByParser);
+
+ return new ${namespace}Element(qName, doc);
+#else
+ return 0;
+#endif
+}
+
+} // namespace
+
+END
+;
+
+ close F;
+}
+
+sub printFactoryHeaderFile
+{
+ my $headerPath = shift;
+ my $F;
+ open F, ">$headerPath";
+
+ printLicenseHeader($F);
+
+print F "#ifndef ${namespace}ELEMENTFACTORY_H\n";
+print F "#define ${namespace}ELEMENTFACTORY_H\n\n";
+
+print F "
+namespace WebCore {
+ class Element;
+ class Document;
+ class QualifiedName;
+ class AtomicString;
+}
+
+namespace ${cppNamespace}
+{
+ class ${namespace}Element;
+
+ // The idea behind this class is that there will eventually be a mapping from namespace URIs to ElementFactories that can dispense
+ // elements. In a compound document world, the generic createElement function (will end up being virtual) will be called.
+ class ${namespace}ElementFactory
+ {
+ public:
+ WebCore::Element *createElement(const WebCore::QualifiedName& qName, WebCore::Document *doc, bool createdByParser = true);
+ static ${namespace}Element *create${namespace}Element(const WebCore::QualifiedName& qName, WebCore::Document *doc, bool createdByParser = true);
+ };
+}
+
+#endif
+
+";
+
+ close F;
+}