summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/dom
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/dom')
-rw-r--r--Source/WebCore/dom/Attr.cpp2
-rw-r--r--Source/WebCore/dom/Attr.h2
-rw-r--r--Source/WebCore/dom/CDATASection.cpp2
-rw-r--r--Source/WebCore/dom/CDATASection.h2
-rw-r--r--Source/WebCore/dom/CheckedRadioButtons.cpp2
-rw-r--r--Source/WebCore/dom/Clipboard.h7
-rw-r--r--Source/WebCore/dom/Clipboard.idl2
-rw-r--r--Source/WebCore/dom/Comment.cpp2
-rw-r--r--Source/WebCore/dom/Comment.h2
-rw-r--r--Source/WebCore/dom/ContainerNode.cpp76
-rw-r--r--Source/WebCore/dom/DOMAllInOne.cpp5
-rw-r--r--Source/WebCore/dom/DOMImplementation.cpp3
-rw-r--r--Source/WebCore/dom/DataTransferItem.cpp43
-rw-r--r--Source/WebCore/dom/DataTransferItem.h62
-rw-r--r--Source/WebCore/dom/DataTransferItem.idl43
-rw-r--r--Source/WebCore/dom/DataTransferItems.h62
-rw-r--r--Source/WebCore/dom/DataTransferItems.idl45
-rw-r--r--Source/WebCore/dom/DatasetDOMStringMap.cpp27
-rw-r--r--Source/WebCore/dom/Document.cpp562
-rw-r--r--Source/WebCore/dom/Document.h173
-rw-r--r--Source/WebCore/dom/Document.idl4
-rw-r--r--Source/WebCore/dom/DocumentFragment.cpp4
-rw-r--r--Source/WebCore/dom/DocumentFragment.h7
-rw-r--r--Source/WebCore/dom/DocumentMarker.h39
-rw-r--r--Source/WebCore/dom/DocumentMarkerController.cpp88
-rw-r--r--Source/WebCore/dom/DocumentMarkerController.h21
-rw-r--r--Source/WebCore/dom/DocumentOrderedMap.cpp17
-rw-r--r--Source/WebCore/dom/DocumentOrderedMap.h10
-rw-r--r--Source/WebCore/dom/DynamicNodeList.cpp5
-rw-r--r--Source/WebCore/dom/DynamicNodeList.h2
-rw-r--r--Source/WebCore/dom/Element.cpp123
-rw-r--r--Source/WebCore/dom/Element.h20
-rw-r--r--Source/WebCore/dom/Element.idl4
-rw-r--r--Source/WebCore/dom/ElementRareData.h4
-rw-r--r--Source/WebCore/dom/Event.cpp25
-rw-r--r--Source/WebCore/dom/Event.h34
-rw-r--r--Source/WebCore/dom/EventDispatcher.cpp394
-rw-r--r--Source/WebCore/dom/EventDispatcher.h82
-rw-r--r--Source/WebCore/dom/EventNames.h2
-rw-r--r--Source/WebCore/dom/EventQueue.cpp28
-rw-r--r--Source/WebCore/dom/EventQueue.h3
-rw-r--r--Source/WebCore/dom/EventTarget.cpp5
-rw-r--r--Source/WebCore/dom/EventTarget.h2
-rw-r--r--Source/WebCore/dom/ExceptionCode.h6
-rw-r--r--Source/WebCore/dom/InputElement.cpp24
-rw-r--r--Source/WebCore/dom/InputElement.h2
-rw-r--r--Source/WebCore/dom/KeyboardEvent.cpp12
-rw-r--r--Source/WebCore/dom/KeyboardEvent.h19
-rw-r--r--Source/WebCore/dom/MessagePort.cpp8
-rw-r--r--Source/WebCore/dom/MouseEvent.cpp80
-rw-r--r--Source/WebCore/dom/MouseEvent.h31
-rw-r--r--Source/WebCore/dom/MouseRelatedEvent.cpp101
-rw-r--r--Source/WebCore/dom/MouseRelatedEvent.h10
-rw-r--r--Source/WebCore/dom/NamedNodeMap.cpp6
-rw-r--r--Source/WebCore/dom/NamedNodeMap.idl1
-rw-r--r--Source/WebCore/dom/Node.cpp630
-rw-r--r--Source/WebCore/dom/Node.h86
-rw-r--r--Source/WebCore/dom/NodeFilter.h9
-rw-r--r--Source/WebCore/dom/NodeList.h3
-rw-r--r--Source/WebCore/dom/NodeList.idl1
-rw-r--r--Source/WebCore/dom/NodeRareData.h11
-rw-r--r--Source/WebCore/dom/NodeRenderStyle.h6
-rw-r--r--Source/WebCore/dom/Notation.cpp2
-rw-r--r--Source/WebCore/dom/Notation.h2
-rw-r--r--Source/WebCore/dom/Position.cpp63
-rw-r--r--Source/WebCore/dom/Position.h3
-rw-r--r--Source/WebCore/dom/PositionIterator.cpp7
-rw-r--r--Source/WebCore/dom/ProcessingInstruction.cpp2
-rw-r--r--Source/WebCore/dom/ProcessingInstruction.h2
-rw-r--r--Source/WebCore/dom/QualifiedName.h6
-rw-r--r--Source/WebCore/dom/Range.cpp70
-rw-r--r--Source/WebCore/dom/Range.h6
-rw-r--r--Source/WebCore/dom/ScriptElement.cpp40
-rw-r--r--Source/WebCore/dom/ScriptElement.h4
-rw-r--r--Source/WebCore/dom/ScriptExecutionContext.cpp2
-rw-r--r--Source/WebCore/dom/ScriptExecutionContext.h2
-rw-r--r--Source/WebCore/dom/ScriptRunner.cpp (renamed from Source/WebCore/dom/AsyncScriptRunner.cpp)53
-rw-r--r--Source/WebCore/dom/ScriptRunner.h (renamed from Source/WebCore/dom/AsyncScriptRunner.h)27
-rw-r--r--Source/WebCore/dom/SelectElement.cpp167
-rw-r--r--Source/WebCore/dom/SelectElement.h2
-rw-r--r--Source/WebCore/dom/ShadowRoot.cpp52
-rw-r--r--Source/WebCore/dom/ShadowRoot.h55
-rw-r--r--Source/WebCore/dom/StringCallback.cpp71
-rw-r--r--Source/WebCore/dom/StringCallback.h52
-rw-r--r--Source/WebCore/dom/StringCallback.idl37
-rw-r--r--Source/WebCore/dom/StyleElement.cpp6
-rw-r--r--Source/WebCore/dom/StyledElement.cpp17
-rw-r--r--Source/WebCore/dom/Text.cpp2
-rw-r--r--Source/WebCore/dom/Text.h2
-rw-r--r--Source/WebCore/dom/TreeScope.cpp170
-rw-r--r--Source/WebCore/dom/TreeScope.h102
-rw-r--r--Source/WebCore/dom/UIEvent.cpp4
-rw-r--r--Source/WebCore/dom/UIEvent.h4
-rw-r--r--Source/WebCore/dom/ViewportArguments.cpp18
-rw-r--r--Source/WebCore/dom/ViewportArguments.h7
-rw-r--r--Source/WebCore/dom/WheelEvent.cpp31
-rw-r--r--Source/WebCore/dom/WheelEvent.h9
-rw-r--r--Source/WebCore/dom/XMLDocumentParser.cpp2
-rw-r--r--Source/WebCore/dom/XMLDocumentParserLibxml2.cpp30
-rw-r--r--Source/WebCore/dom/XMLDocumentParserQt.cpp6
-rw-r--r--Source/WebCore/dom/default/PlatformMessagePortChannel.h4
-rwxr-xr-xSource/WebCore/dom/make_names.pl59
102 files changed, 2894 insertions, 1399 deletions
diff --git a/Source/WebCore/dom/Attr.cpp b/Source/WebCore/dom/Attr.cpp
index 6500a97..e3ae348 100644
--- a/Source/WebCore/dom/Attr.cpp
+++ b/Source/WebCore/dom/Attr.cpp
@@ -152,7 +152,7 @@ PassRefPtr<Node> Attr::cloneNode(bool /*deep*/)
}
// DOM Section 1.1.1
-bool Attr::childTypeAllowed(NodeType type)
+bool Attr::childTypeAllowed(NodeType type) const
{
switch (type) {
case TEXT_NODE:
diff --git a/Source/WebCore/dom/Attr.h b/Source/WebCore/dom/Attr.h
index e76d2fa..217a0c3 100644
--- a/Source/WebCore/dom/Attr.h
+++ b/Source/WebCore/dom/Attr.h
@@ -79,7 +79,7 @@ private:
virtual PassRefPtr<Node> cloneNode(bool deep);
virtual bool isAttributeNode() const { return true; }
- virtual bool childTypeAllowed(NodeType);
+ virtual bool childTypeAllowed(NodeType) const;
virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
diff --git a/Source/WebCore/dom/CDATASection.cpp b/Source/WebCore/dom/CDATASection.cpp
index d73054e..33a3acc 100644
--- a/Source/WebCore/dom/CDATASection.cpp
+++ b/Source/WebCore/dom/CDATASection.cpp
@@ -51,7 +51,7 @@ PassRefPtr<Node> CDATASection::cloneNode(bool /*deep*/)
return create(document(), data());
}
-bool CDATASection::childTypeAllowed(NodeType)
+bool CDATASection::childTypeAllowed(NodeType) const
{
return false;
}
diff --git a/Source/WebCore/dom/CDATASection.h b/Source/WebCore/dom/CDATASection.h
index 5cf07e1..d7aca9d 100644
--- a/Source/WebCore/dom/CDATASection.h
+++ b/Source/WebCore/dom/CDATASection.h
@@ -37,7 +37,7 @@ private:
virtual String nodeName() const;
virtual NodeType nodeType() const;
virtual PassRefPtr<Node> cloneNode(bool deep);
- virtual bool childTypeAllowed(NodeType);
+ virtual bool childTypeAllowed(NodeType) const;
virtual PassRefPtr<Text> virtualCreate(const String&);
};
diff --git a/Source/WebCore/dom/CheckedRadioButtons.cpp b/Source/WebCore/dom/CheckedRadioButtons.cpp
index 3cf8848..20662a2 100644
--- a/Source/WebCore/dom/CheckedRadioButtons.cpp
+++ b/Source/WebCore/dom/CheckedRadioButtons.cpp
@@ -77,7 +77,7 @@ void CheckedRadioButtons::removeButton(HTMLFormControlElement* element)
if (it == m_nameToCheckedRadioButtonMap->end() || it->second != element)
return;
- InputElement* inputElement = toInputElement(element);
+ InputElement* inputElement = element->toInputElement();
ASSERT_UNUSED(inputElement, inputElement);
ASSERT(inputElement->isChecked());
ASSERT(element->isRadioButton());
diff --git a/Source/WebCore/dom/Clipboard.h b/Source/WebCore/dom/Clipboard.h
index b8eadfb..40141af 100644
--- a/Source/WebCore/dom/Clipboard.h
+++ b/Source/WebCore/dom/Clipboard.h
@@ -33,6 +33,7 @@
namespace WebCore {
+ class DataTransferItems;
class DragData;
class FileList;
class Frame;
@@ -84,6 +85,7 @@ namespace WebCore {
virtual bool hasData() = 0;
void setAccessPolicy(ClipboardAccessPolicy);
+ ClipboardAccessPolicy policy() const { return m_policy; }
DragOperation sourceOperation() const;
DragOperation destinationOperation() const;
@@ -91,11 +93,14 @@ namespace WebCore {
void setDestinationOperation(DragOperation);
void setDragHasStarted() { m_dragStarted = true; }
+
+#if ENABLE(DATA_TRANSFER_ITEMS)
+ virtual PassRefPtr<DataTransferItems> items() = 0;
+#endif
protected:
Clipboard(ClipboardAccessPolicy, ClipboardType);
- ClipboardAccessPolicy policy() const { return m_policy; }
bool dragStarted() const { return m_dragStarted; }
private:
diff --git a/Source/WebCore/dom/Clipboard.idl b/Source/WebCore/dom/Clipboard.idl
index 1024a36..d5bb331 100644
--- a/Source/WebCore/dom/Clipboard.idl
+++ b/Source/WebCore/dom/Clipboard.idl
@@ -42,6 +42,8 @@ module core {
[RequiresAllArguments] boolean setData(in DOMString type, in DOMString data);
[Custom] void setDragImage(in HTMLImageElement image, in long x, in long y)
raises(DOMException);
+
+ readonly attribute [Conditional=DATA_TRANSFER_ITEMS, EnabledAtRuntime=DataTransferItems] DataTransferItems items;
};
}
diff --git a/Source/WebCore/dom/Comment.cpp b/Source/WebCore/dom/Comment.cpp
index 00f1724..92cffed 100644
--- a/Source/WebCore/dom/Comment.cpp
+++ b/Source/WebCore/dom/Comment.cpp
@@ -51,7 +51,7 @@ PassRefPtr<Node> Comment::cloneNode(bool /*deep*/)
return create(document(), data());
}
-bool Comment::childTypeAllowed(NodeType)
+bool Comment::childTypeAllowed(NodeType) const
{
return false;
}
diff --git a/Source/WebCore/dom/Comment.h b/Source/WebCore/dom/Comment.h
index a0210c4..9db1f31 100644
--- a/Source/WebCore/dom/Comment.h
+++ b/Source/WebCore/dom/Comment.h
@@ -37,7 +37,7 @@ private:
virtual String nodeName() const;
virtual NodeType nodeType() const;
virtual PassRefPtr<Node> cloneNode(bool deep);
- virtual bool childTypeAllowed(NodeType);
+ virtual bool childTypeAllowed(NodeType) const;
};
} // namespace WebCore
diff --git a/Source/WebCore/dom/ContainerNode.cpp b/Source/WebCore/dom/ContainerNode.cpp
index 7424875..2d22fa9 100644
--- a/Source/WebCore/dom/ContainerNode.cpp
+++ b/Source/WebCore/dom/ContainerNode.cpp
@@ -56,15 +56,19 @@ static NodeCallbackQueue* s_postAttachCallbackQueue;
static size_t s_attachDepth;
static bool s_shouldReEnableMemoryCacheCallsAfterAttach;
+static inline void collectNodes(Node* node, NodeVector& nodes)
+{
+ for (Node* child = node->firstChild(); child; child = child->nextSibling())
+ nodes.append(child);
+}
+
static void collectTargetNodes(Node* node, NodeVector& nodes)
{
if (node->nodeType() != Node::DOCUMENT_FRAGMENT_NODE) {
nodes.append(node);
return;
}
-
- for (Node* child = node->firstChild(); child; child = child->nextSibling())
- nodes.append(child);
+ collectNodes(node, nodes);
}
void ContainerNode::removeAllChildren()
@@ -75,8 +79,7 @@ void ContainerNode::removeAllChildren()
void ContainerNode::takeAllChildrenFrom(ContainerNode* oldParent)
{
NodeVector children;
- for (Node* child = oldParent->firstChild(); child; child = child->nextSibling())
- children.append(child);
+ collectNodes(oldParent, children);
oldParent->removeAllChildren();
for (unsigned i = 0; i < children.size(); ++i) {
@@ -101,7 +104,7 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce
{
// Check that this node is not "floating".
// If it is, it can be deleted as a side effect of sending mutation events.
- ASSERT(refCount() || parentNode());
+ ASSERT(refCount() || parentOrHostNode());
ec = 0;
@@ -158,7 +161,8 @@ bool ContainerNode::insertBefore(PassRefPtr<Node> newChild, Node* refChild, Exce
InspectorInstrumentation::willInsertDOMNode(document(), child, this);
#endif
- child->setDocumentRecursively(document());
+ child->setTreeScopeRecursively(treeScope());
+
insertBeforeCommon(next.get(), child);
// Send notification about the children change.
@@ -241,7 +245,7 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce
{
// Check that this node is not "floating".
// If it is, it can be deleted as a side effect of sending mutation events.
- ASSERT(refCount() || parentNode());
+ ASSERT(refCount() || parentOrHostNode());
ec = 0;
@@ -307,7 +311,7 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce
InspectorInstrumentation::willInsertDOMNode(document(), child.get(), this);
#endif
- child->setDocumentRecursively(document());
+ child->setTreeScopeRecursively(treeScope());
// Add child after "prev".
forbidEventDispatch();
@@ -384,8 +388,7 @@ static void willRemoveChildren(ContainerNode* container)
container->document()->incDOMTreeVersion();
NodeVector children;
- for (Node* n = container->firstChild(); n; n = n->nextSibling())
- children.append(n);
+ collectNodes(container, children);
for (NodeVector::const_iterator it = children.begin(); it != children.end(); it++) {
Node* child = it->get();
@@ -399,7 +402,7 @@ 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() || parentNode());
+ ASSERT(refCount() || parentOrHostNode());
ec = 0;
@@ -531,21 +534,31 @@ void ContainerNode::removeChildren()
m_firstChild = next;
if (n == m_lastChild)
m_lastChild = 0;
-
- if (n->attached())
- n->detach();
-
removedChildren.append(n.release());
}
- allowEventDispatch();
size_t removedChildrenCount = removedChildren.size();
+ size_t i;
+
+ // Detach the nodes only after properly removed from the tree because
+ // a. detaching requires a proper DOM tree (for counters and quotes for
+ // example) and during the previous loop the next sibling still points to
+ // the node being removed while the node being removed does not point back
+ // and does not point to the same parent as its next sibling.
+ // b. destroying Renderers of standalone nodes is sometimes faster.
+ for (i = 0; i < removedChildrenCount; ++i) {
+ Node* removedChild = removedChildren[i].get();
+ if (removedChild->attached())
+ removedChild->detach();
+ }
+
+ allowEventDispatch();
// Dispatch a single post-removal mutation event denoting a modified subtree.
childrenChanged(false, 0, 0, -static_cast<int>(removedChildrenCount));
dispatchSubtreeModifiedEvent();
- for (size_t i = 0; i < removedChildrenCount; ++i) {
+ for (i = 0; i < removedChildrenCount; ++i) {
Node* removedChild = removedChildren[i].get();
if (removedChild->inDocument())
removedChild->removedFromDocument();
@@ -559,7 +572,7 @@ bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bo
{
// Check that this node is not "floating".
// If it is, it can be deleted as a side effect of sending mutation events.
- ASSERT(refCount() || parentNode());
+ ASSERT(refCount() || parentOrHostNode());
ec = 0;
@@ -597,7 +610,7 @@ bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bo
InspectorInstrumentation::willInsertDOMNode(document(), child, this);
#endif
- child->setDocumentRecursively(document());
+ child->setTreeScopeRecursively(treeScope());
// Append child to the end of the list
forbidEventDispatch();
@@ -735,8 +748,16 @@ void ContainerNode::insertedIntoDocument()
{
Node::insertedIntoDocument();
insertedIntoTree(false);
- for (Node* child = m_firstChild; child; child = child->nextSibling())
+
+ // Determine set of children before operating on any of them.
+ NodeVector children;
+ collectNodes(this, children);
+
+ NodeVector::iterator it;
+ for (it = children.begin(); it != children.end() && inDocument(); ++it) {
+ Node* child = it->get();
child->insertedIntoDocument();
+ }
}
void ContainerNode::removedFromDocument()
@@ -778,9 +799,16 @@ void ContainerNode::childrenChanged(bool changedByParser, Node* beforeChange, No
void ContainerNode::cloneChildNodes(ContainerNode *clone)
{
// disable the delete button so it's elements are not serialized into the markup
- bool isEditorEnabled = document()->frame() && document()->frame()->editor()->canEdit();
- if (isEditorEnabled)
- document()->frame()->editor()->deleteButtonController()->disable();
+ bool isEditorEnabled = false;
+ if (document()->frame() && document()->frame()->editor()->canEdit()) {
+ SelectionController* selection = document()->frame()->selection();
+ Element* root = selection ? selection->rootEditableElement() : 0;
+ isEditorEnabled = root && isDescendantOf(root);
+
+ if (isEditorEnabled)
+ document()->frame()->editor()->deleteButtonController()->disable();
+ }
+
ExceptionCode ec = 0;
for (Node* n = firstChild(); n && !ec; n = n->nextSibling())
clone->appendChild(n->cloneNode(true), ec);
diff --git a/Source/WebCore/dom/DOMAllInOne.cpp b/Source/WebCore/dom/DOMAllInOne.cpp
index c88aecf..4a51d90 100644
--- a/Source/WebCore/dom/DOMAllInOne.cpp
+++ b/Source/WebCore/dom/DOMAllInOne.cpp
@@ -26,7 +26,6 @@
// This all-in-one cpp file cuts down on template bloat to allow us to build our Windows release build.
#include "ActiveDOMObject.cpp"
-#include "AsyncScriptRunner.cpp"
#include "Attr.cpp"
#include "Attribute.cpp"
#include "BeforeProcessEvent.cpp"
@@ -70,6 +69,7 @@
#include "ErrorEvent.cpp"
#include "Event.cpp"
#include "EventContext.cpp"
+#include "EventDispatcher.cpp"
#include "EventNames.cpp"
#include "EventQueue.cpp"
#include "EventTarget.cpp"
@@ -104,9 +104,11 @@
#include "ScopedEventQueue.cpp"
#include "ScriptElement.cpp"
#include "ScriptExecutionContext.cpp"
+#include "ScriptRunner.cpp"
#include "ScriptableDocumentParser.cpp"
#include "SelectElement.cpp"
#include "SelectorNodeList.cpp"
+#include "ShadowRoot.cpp"
#include "SpaceSplitString.cpp"
#include "StaticHashSetNodeList.cpp"
#include "StaticNodeList.cpp"
@@ -120,6 +122,7 @@
#include "TouchList.cpp"
#include "TransformSourceLibxslt.cpp"
#include "Traversal.cpp"
+#include "TreeScope.cpp"
#include "TreeWalker.cpp"
#include "UIEvent.cpp"
#include "UIEventWithKeyState.cpp"
diff --git a/Source/WebCore/dom/DOMImplementation.cpp b/Source/WebCore/dom/DOMImplementation.cpp
index 3ba1137..782f203 100644
--- a/Source/WebCore/dom/DOMImplementation.cpp
+++ b/Source/WebCore/dom/DOMImplementation.cpp
@@ -262,7 +262,8 @@ PassRefPtr<Document> DOMImplementation::createDocument(const String& namespaceUR
// WRONG_DOCUMENT_ERR: Raised if doctype has already been used with a different document or was
// created from a different implementation.
// Hixie's interpretation of the DOM Core spec suggests we should prefer
- // other exceptions to WRONG_DOCUMENT_ERR (based on order mentioned in spec).
+ // other exceptions to WRONG_DOCUMENT_ERR (based on order mentioned in spec),
+ // but this matches the new DOM Core spec (http://www.w3.org/TR/domcore/).
if (doctype && doctype->document()) {
ec = WRONG_DOCUMENT_ERR;
return 0;
diff --git a/Source/WebCore/dom/DataTransferItem.cpp b/Source/WebCore/dom/DataTransferItem.cpp
new file mode 100644
index 0000000..8eec869
--- /dev/null
+++ b/Source/WebCore/dom/DataTransferItem.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DataTransferItem.h"
+
+#if ENABLE(DATA_TRANSFER_ITEMS)
+
+namespace WebCore {
+
+const char DataTransferItem::kindString[] = "string";
+const char DataTransferItem::kindFile[] = "file";
+
+} // namespace WebCore
+
+#endif // ENABLE(DATA_TRANSFER_ITEMS)
diff --git a/Source/WebCore/dom/DataTransferItem.h b/Source/WebCore/dom/DataTransferItem.h
new file mode 100644
index 0000000..d648c56
--- /dev/null
+++ b/Source/WebCore/dom/DataTransferItem.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DataTransferItem_h
+#define DataTransferItem_h
+
+#if ENABLE(DATA_TRANSFER_ITEMS)
+
+#include <wtf/Forward.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class Blob;
+class StringCallback;
+
+class DataTransferItem : public RefCounted<DataTransferItem> {
+public:
+ ~DataTransferItem() {}
+
+ static const char kindString[];
+ static const char kindFile[];
+
+ virtual String kind() const = 0;
+ virtual String type() const = 0;
+
+ virtual void getAsString(PassRefPtr<StringCallback>) = 0;
+ virtual PassRefPtr<Blob> getAsFile() = 0;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(DATA_TRANSFER_ITEMS)
+
+#endif // DataTransferItem_h
diff --git a/Source/WebCore/dom/DataTransferItem.idl b/Source/WebCore/dom/DataTransferItem.idl
new file mode 100644
index 0000000..accaf50
--- /dev/null
+++ b/Source/WebCore/dom/DataTransferItem.idl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module core {
+
+ interface [
+ Conditional=DATA_TRANSFER_ITEMS
+ ] DataTransferItem {
+ readonly attribute DOMString kind;
+ readonly attribute DOMString type;
+
+ void getAsString(in [Callback] StringCallback callback);
+ Blob getAsFile();
+ };
+
+}
diff --git a/Source/WebCore/dom/DataTransferItems.h b/Source/WebCore/dom/DataTransferItems.h
new file mode 100644
index 0000000..0873384
--- /dev/null
+++ b/Source/WebCore/dom/DataTransferItems.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DataTransferItems_h
+#define DataTransferItems_h
+
+#if ENABLE(DATA_TRANSFER_ITEMS)
+
+#include <wtf/Forward.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class DataTransferItem;
+
+typedef int ExceptionCode;
+
+class DataTransferItems : public RefCounted<DataTransferItems> {
+public:
+ ~DataTransferItems() {}
+
+ virtual unsigned long length() const = 0;
+ virtual PassRefPtr<DataTransferItem> item(unsigned long index) const = 0;
+ virtual void deleteItem(unsigned long index, ExceptionCode&) = 0;
+ virtual void clear() = 0;
+
+ virtual void add(const String& data, const String& type, ExceptionCode&) = 0;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(DATA_TRANSFER_ITEMS)
+
+#endif // DataTransferItems_h
+
diff --git a/Source/WebCore/dom/DataTransferItems.idl b/Source/WebCore/dom/DataTransferItems.idl
new file mode 100644
index 0000000..1cb36b8
--- /dev/null
+++ b/Source/WebCore/dom/DataTransferItems.idl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module core {
+
+ interface [
+ Conditional=DATA_TRANSFER_ITEMS,
+ HasIndexGetter,
+ CustomDeleteProperty,
+ ] DataTransferItems {
+ readonly attribute long length;
+ DataTransferItem item(in unsigned long index) getter;
+
+ void clear();
+ void add(in DOMString data, in DOMString type) raises(DOMException);
+ };
+
+}
diff --git a/Source/WebCore/dom/DatasetDOMStringMap.cpp b/Source/WebCore/dom/DatasetDOMStringMap.cpp
index 6359d55..a143743 100644
--- a/Source/WebCore/dom/DatasetDOMStringMap.cpp
+++ b/Source/WebCore/dom/DatasetDOMStringMap.cpp
@@ -72,13 +72,30 @@ static String convertAttributeNameToPropertyName(const String& name)
static bool propertyNameMatchesAttributeName(const String& propertyName, const String& attributeName)
{
- // FIXME: This should be able to match without creating a new string.
-
- if (!isValidAttributeName(attributeName))
+ if (!attributeName.startsWith("data-"))
return false;
- String convertedName = convertAttributeNameToPropertyName(attributeName);
- return (convertedName == propertyName);
+ const UChar* property = propertyName.characters();
+ const UChar* attribute = attributeName.characters();
+ unsigned propertyLength = propertyName.length();
+ unsigned attributeLength = attributeName.length();
+
+ unsigned a = 5;
+ unsigned p = 0;
+ bool wordBoundary = false;
+ while (a < attributeLength && p < propertyLength) {
+ if (attribute[a] == '-' && a + 1 < attributeLength && attribute[a + 1] != '-')
+ wordBoundary = true;
+ else {
+ if ((wordBoundary ? toASCIIUpper(attribute[a]) : attribute[a]) != property[p])
+ return false;
+ p++;
+ wordBoundary = false;
+ }
+ a++;
+ }
+
+ return (a == attributeLength && p == propertyLength);
}
static bool isValidPropertyName(const String& name)
diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp
index a2a8040..638b4ab 100644
--- a/Source/WebCore/dom/Document.cpp
+++ b/Source/WebCore/dom/Document.cpp
@@ -7,7 +7,6 @@
* Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
* Copyright (C) 2008, 2009 Google Inc. All rights reserved.
* Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
- * Copyright (C) Research In Motion, Limited 2010-2011.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -30,7 +29,6 @@
#include "AXObjectCache.h"
#include "AnimationController.h"
-#include "AsyncScriptRunner.h"
#include "Attr.h"
#include "Attribute.h"
#include "CDATASection.h"
@@ -44,6 +42,7 @@
#include "ChromeClient.h"
#include "Comment.h"
#include "Console.h"
+#include "ContentSecurityPolicy.h"
#include "CookieJar.h"
#include "CustomEvent.h"
#include "DateComponents.h"
@@ -120,14 +119,16 @@
#include "RegisteredEventListener.h"
#include "RenderArena.h"
#include "RenderLayer.h"
+#include "RenderLayerBacking.h"
#include "RenderTextControl.h"
#include "RenderView.h"
#include "RenderWidget.h"
-#include "ScopedEventQueue.h"
+#include "ScopedEventQueue.h"
#include "ScriptCallStack.h"
#include "ScriptController.h"
#include "ScriptElement.h"
#include "ScriptEventListener.h"
+#include "ScriptRunner.h"
#include "SecurityOrigin.h"
#include "SegmentedString.h"
#include "SelectionController.h"
@@ -333,7 +334,7 @@ static Widget* widgetForNode(Node* focusedNode)
static bool acceptsEditingFocus(Node* node)
{
ASSERT(node);
- ASSERT(node->isContentEditable());
+ ASSERT(node->rendererIsEditable());
Node* root = node->rootEditableElement();
Frame* frame = node->document()->frame();
@@ -358,7 +359,7 @@ static bool disableRangeMutation(Page* page)
static HashSet<Document*>* documentsThatNeedStyleRecalc = 0;
-class DocumentWeakReference : public ThreadSafeShared<DocumentWeakReference> {
+class DocumentWeakReference : public ThreadSafeRefCounted<DocumentWeakReference> {
public:
static PassRefPtr<DocumentWeakReference> create(Document* document)
{
@@ -387,11 +388,14 @@ private:
Document* m_document;
};
+uint64_t Document::s_globalTreeVersion = 0;
+
Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
- : ContainerNode(0)
+ : TreeScope(this)
+ , m_guardRefCount(0)
, m_compatibilityMode(NoQuirksMode)
, m_compatibilityModeLocked(false)
- , m_domTreeVersion(0)
+ , m_domTreeVersion(++s_globalTreeVersion)
#ifdef ANDROID_STYLE_VERSION
, m_styleVersion(0)
#endif
@@ -403,19 +407,16 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
, m_containsValidityStyleRules(false)
, m_updateFocusAppearanceRestoresSelection(false)
, m_ignoreDestructiveWriteCount(0)
- , m_title("")
- , m_rawTitle("")
, m_titleSetExplicitly(false)
, m_updateFocusAppearanceTimer(this, &Document::updateFocusAppearanceTimerFired)
, m_startTime(currentTime())
, m_overMinimumLayoutThreshold(false)
, m_extraLayoutDelay(0)
- , m_asyncScriptRunner(AsyncScriptRunner::create(this))
+ , m_scriptRunner(ScriptRunner::create(this))
, m_xmlVersion("1.0")
, m_xmlStandalone(false)
, m_savedRenderer(0)
, m_designMode(inherit)
- , m_selfOnlyRefCount(0)
#if ENABLE(SVG)
, m_svgExtensions(0)
#endif
@@ -423,7 +424,6 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
, m_hasDashboardRegions(false)
, m_dashboardRegionsDirty(false)
#endif
- , m_accessKeyMapValid(false)
, m_createRenderers(true)
, m_inPageCache(false)
, m_useSecureKeyboardEntryWhenActive(false)
@@ -431,10 +431,6 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
, m_isHTML(isHTML)
, m_usesViewSourceStyles(false)
, m_sawElementsInKnownNamespaces(false)
- , m_numNodeListCaches(0)
-#if USE(JSC)
- , m_normalWorldWrapperCache(0)
-#endif
, m_usingGeolocation(false)
, m_eventQueue(EventQueue::create(this))
#if ENABLE(WML)
@@ -443,7 +439,6 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
, m_weakReference(DocumentWeakReference::create(this))
, m_idAttributeName(idAttr)
#if ENABLE(FULLSCREEN_API)
- , m_isFullScreen(0)
, m_areKeysEnabledInFullScreen(0)
, m_fullScreenRenderer(0)
, m_fullScreenChangeDelayTimer(this, &Document::fullScreenChangeDelayTimerFired)
@@ -454,7 +449,6 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
, m_writingModeSetOnDocumentElement(false)
, m_writeRecursionIsTooDeep(false)
, m_writeRecursionDepth(0)
- , m_pendingTasksTimer(this, &Document::pendingTasksTimerFired)
{
m_document = this;
@@ -466,7 +460,6 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
m_ignoreAutofocus = false;
m_frame = frame;
- m_documentLoader = frame ? frame->loader()->activeDocumentLoader() : 0;
// We depend on the url getting immediately set in subframes, but we
// also depend on the url NOT getting immediately set in opened windows.
@@ -504,7 +497,7 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
m_usesLinkRules = false;
m_gotoAnchorNeededAfterStylesheetsLoad = false;
-
+
m_didCalculateStyleSelector = false;
m_hasDirtyStyleSelector = false;
m_pendingStylesheets = 0;
@@ -530,52 +523,6 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
#endif
}
-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.
- selfOnlyRef();
-
- // 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;
-#if ENABLE(FULLSCREEN_API)
- m_fullScreenElement = 0;
-#endif
-
- // removeAllChildren() doesn't always unregister IDs, do it upfront to avoid having stale references in the map.
- m_elementsById.clear();
-
- removeAllChildren();
-
- m_markers->detach();
-
- detachParser();
-
- m_cssCanvasElements.clear();
-
-#ifndef NDEBUG
- m_inRemovedLastRefFunction = false;
-#endif
-
- selfOnlyDeref();
- } else {
-#ifndef NDEBUG
- m_deletionHasBegun = true;
-#endif
- delete this;
- }
-}
-
Document::~Document()
{
ASSERT(!renderer());
@@ -583,15 +530,12 @@ Document::~Document()
ASSERT(!m_savedRenderer);
ASSERT(m_ranges.isEmpty());
ASSERT(!m_styleRecalcTimer.isActive());
+ ASSERT(!m_parentTreeScope);
- m_asyncScriptRunner.clear();
+ m_scriptRunner.clear();
removeAllEventListeners();
-#if USE(JSC)
- destroyAllWrapperCaches();
-#endif
-
// Currently we believe that Document can never outlive the parser.
// Although the Document may be replaced synchronously, DocumentParsers
// generally keep at least one reference to an Element which would in turn
@@ -635,41 +579,68 @@ Document::~Document()
m_implementation->ownerDocumentDestroyed();
}
-MediaQueryMatcher* Document::mediaQueryMatcher()
+void Document::removedLastRef()
{
- if (!m_mediaQueryMatcher)
- m_mediaQueryMatcher = MediaQueryMatcher::create(this);
- return m_mediaQueryMatcher.get();
-}
+ ASSERT(!m_deletionHasBegun);
+ if (m_guardRefCount) {
+ // If removing a child removes the last self-only ref, we don't
+ // want the scope to be destructed until after
+ // removeAllChildren returns, so we guard ourselves with an
+ // extra self-only ref.
+ guardRef();
-#if USE(JSC)
-Document::JSWrapperCache* Document::createWrapperCache(DOMWrapperWorld* world)
-{
- JSWrapperCache* wrapperCache = new JSWrapperCache;
- m_wrapperCacheMap.set(world, wrapperCache);
- if (world->isNormal()) {
- ASSERT(!m_normalWorldWrapperCache);
- m_normalWorldWrapperCache = wrapperCache;
+ // 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;
+#if ENABLE(FULLSCREEN_API)
+ m_fullScreenElement = 0;
+#endif
+
+ // removeAllChildren() doesn't always unregister IDs,
+ // so tear down scope information upfront to avoid having stale references in the map.
+ destroyTreeScopeData();
+ removeAllChildren();
+
+ m_markers->detach();
+
+ detachParser();
+
+ m_cssCanvasElements.clear();
+
+#if ENABLE(REQUEST_ANIMATION_FRAME)
+ // FIXME: consider using ActiveDOMObject.
+ m_scriptedAnimationController = 0;
+#endif
+
+#ifndef NDEBUG
+ m_inRemovedLastRefFunction = false;
+#endif
+
+ guardDeref();
+ } else {
+#ifndef NDEBUG
+ m_deletionHasBegun = true;
+#endif
+ delete this;
}
- world->didCreateWrapperCache(this);
- return wrapperCache;
}
-void Document::destroyWrapperCache(DOMWrapperWorld* world)
+Element* Document::getElementById(const AtomicString& id) const
{
- Document::JSWrapperCache* wrappers = wrapperCacheMap().take(world);
- ASSERT(wrappers);
- delete wrappers;
- world->didDestroyWrapperCache(this);
+ return TreeScope::getElementById(id);
}
-void Document::destroyAllWrapperCaches()
+MediaQueryMatcher* Document::mediaQueryMatcher()
{
- JSWrapperCacheMap& wrapperCacheMap = this->wrapperCacheMap();
- while (!wrapperCacheMap.isEmpty())
- destroyWrapperCache(wrapperCacheMap.begin()->first);
+ if (!m_mediaQueryMatcher)
+ m_mediaQueryMatcher = MediaQueryMatcher::create(this);
+ return m_mediaQueryMatcher.get();
}
-#endif
void Document::setCompatibilityMode(CompatibilityMode mode)
{
@@ -711,15 +682,13 @@ void Document::setDocType(PassRefPtr<DocumentType> docType)
ASSERT(!m_docType || !docType);
m_docType = docType;
if (m_docType)
- m_docType->setDocument(this);
+ m_docType->setTreeScope(this);
+
#ifdef ANDROID_META_SUPPORT
if (m_docType && !ownerElement()
&& m_docType->publicId().startsWith("-//wapforum//dtd xhtml mobile 1.", false)) {
// fit mobile sites directly in the screen
- if (Frame *f = frame())
- f->settings()->setMetadataSettings("width", "device-width");
- if (FrameView* frameView = view())
- PlatformBridge::updateViewport(frameView);
+ processViewport("width=device-width");
}
#endif
}
@@ -733,7 +702,7 @@ DOMImplementation* Document::implementation()
void Document::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
{
- ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
+ TreeScope::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
// Invalidate the document element we have cached in case it was replaced.
m_documentElement = 0;
@@ -951,7 +920,7 @@ PassRefPtr<Node> Document::adoptNode(PassRefPtr<Node> source, ExceptionCode& ec)
source->parentNode()->removeChild(source.get(), ec);
}
- source->setDocumentRecursively(this);
+ source->setTreeScopeRecursively(this);
return source;
}
@@ -1026,13 +995,6 @@ PassRefPtr<Element> Document::createElementNS(const String& namespaceURI, const
return createElement(qName, false);
}
-Element* Document::getElementById(const AtomicString& elementId) const
-{
- if (elementId.isEmpty())
- return 0;
- return m_elementsById.getElementById(elementId.impl(), this);
-}
-
String Document::readyState() const
{
DEFINE_STATIC_LOCAL(const String, loading, ("loading"));
@@ -1259,42 +1221,15 @@ PassRefPtr<Range> Document::caretRangeFromPoint(int x, int y)
return Range::create(this, rangeCompliantPosition, rangeCompliantPosition);
}
-void Document::addElementById(const AtomicString& elementId, Element* element)
-{
- m_elementsById.add(elementId.impl(), element);
-}
-
-void Document::removeElementById(const AtomicString& elementId, Element* element)
-{
- m_elementsById.remove(elementId.impl(), element);
-}
-
-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());
-}
-
/*
* Performs three operations:
* 1. Convert control characters to spaces
* 2. Trim leading and trailing spaces
* 3. Collapse internal whitespace.
*/
-static inline String canonicalizedTitle(Document* document, const String& title)
+static inline StringWithDirection canonicalizedTitle(Document* document, const StringWithDirection& titleWithDirection)
{
+ const String& title = titleWithDirection.string();
const UChar* characters = title.characters();
unsigned length = title.length();
unsigned i;
@@ -1310,7 +1245,7 @@ static inline String canonicalizedTitle(Document* document, const String& title)
}
if (i == length)
- return "";
+ return StringWithDirection();
// Replace control characters with spaces, and backslashes with currency symbols, and collapse whitespace.
bool previousCharWasWS = false;
@@ -1335,53 +1270,62 @@ static inline String canonicalizedTitle(Document* document, const String& title)
}
if (!builderIndex && buffer[builderIndex] == ' ')
- return "";
+ return StringWithDirection();
buffer.shrink(builderIndex + 1);
// Replace the backslashes with currency symbols if the encoding requires it.
document->displayBufferModifiedByEncoding(buffer.characters(), buffer.length());
- return String::adopt(buffer);
+ return StringWithDirection(String::adopt(buffer), titleWithDirection.direction());
}
-void Document::updateTitle()
+void Document::updateTitle(const StringWithDirection& title)
{
+ if (m_rawTitle == title)
+ return;
+
+ m_rawTitle = title;
m_title = canonicalizedTitle(this, m_rawTitle);
if (Frame* f = frame())
f->loader()->setTitle(m_title);
}
-void Document::setTitle(const String& title, Element* titleElement)
+void Document::setTitle(const String& title)
{
- 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()) {
- m_titleElement = createElement(titleTag, false);
- ExceptionCode ec = 0;
- headElement->appendChild(m_titleElement, ec);
- ASSERT(!ec);
- }
+ // Title set by JavaScript -- overrides any title elements.
+ m_titleSetExplicitly = true;
+ if (!isHTMLDocument())
+ m_titleElement = 0;
+ else if (!m_titleElement) {
+ if (HTMLElement* headElement = head()) {
+ m_titleElement = createElement(titleTag, false);
+ ExceptionCode ec = 0;
+ headElement->appendChild(m_titleElement, ec);
+ ASSERT(!ec);
}
- } else if (titleElement != m_titleElement) {
+ }
+
+ // The DOM API has no method of specifying direction, so assume LTR.
+ updateTitle(StringWithDirection(title, LTR));
+
+ if (m_titleElement) {
+ ASSERT(m_titleElement->hasTagName(titleTag));
+ if (m_titleElement->hasTagName(titleTag))
+ static_cast<HTMLTitleElement*>(m_titleElement.get())->setText(title);
+ }
+}
+
+void Document::setTitleElement(const StringWithDirection& title, Element* titleElement)
+{
+ 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_rawTitle == title)
- return;
-
- m_rawTitle = title;
- updateTitle();
-
- if (m_titleSetExplicitly && m_titleElement && m_titleElement->hasTagName(titleTag) && !titleElement)
- static_cast<HTMLTitleElement*>(m_titleElement.get())->setText(m_title);
+ updateTitle(title);
}
void Document::removeTitle(Element* titleElement)
@@ -1397,15 +1341,13 @@ void Document::removeTitle(Element* titleElement)
for (Node* e = headElement->firstChild(); e; e = e->nextSibling())
if (e->hasTagName(titleTag)) {
HTMLTitleElement* titleElement = static_cast<HTMLTitleElement*>(e);
- setTitle(titleElement->text(), titleElement);
+ setTitleElement(titleElement->textWithDirection(), titleElement);
break;
}
}
- if (!m_titleElement && !m_rawTitle.isEmpty()) {
- m_rawTitle = "";
- updateTitle();
- }
+ if (!m_titleElement)
+ updateTitle(StringWithDirection());
}
String Document::nodeName() const
@@ -1476,10 +1418,7 @@ void Document::scheduleStyleRecalc()
documentsThatNeedStyleRecalc->add(this);
// FIXME: Why on earth is this here? This is clearly misplaced.
- if (m_accessKeyMapValid) {
- m_accessKeyMapValid = false;
- m_elementsByAccessKey.clear();
- }
+ invalidateAccessKeyMap();
m_styleRecalcTimer.startOneShot(0);
}
@@ -1529,17 +1468,21 @@ void Document::recalcStyle(StyleChange change)
m_inStyleRecalc = true;
suspendPostAttachCallbacks();
RenderWidget::suspendWidgetHierarchyUpdates();
- if (view())
- view()->pauseScheduledEvents();
+ RefPtr<FrameView> frameView = view();
+ if (frameView) {
+ frameView->pauseScheduledEvents();
+ frameView->beginDeferredRepaints();
+ }
+
#ifdef ANDROID_INSTRUMENT
android::TimeCounter::start(android::TimeCounter::CalculateStyleTimeCounter);
#endif
-
+
ASSERT(!renderer() || renderArena());
if (!renderer() || !renderArena())
goto bail_out;
-
+
if (m_pendingStyleRecalcShouldForce)
change = Force;
@@ -1574,6 +1517,8 @@ bail_out:
clearNeedsStyleRecalc();
clearChildNeedsStyleRecalc();
unscheduleStyleRecalc();
+
+ m_inStyleRecalc = false;
// Pseudo element removal and similar may only work with these flags still set. Reset them after the style recalc.
if (m_styleSelector) {
@@ -1583,11 +1528,12 @@ bail_out:
m_usesLinkRules = m_styleSelector->usesLinkRules();
}
- if (view())
- view()->resumeScheduledEvents();
+ if (frameView) {
+ frameView->resumeScheduledEvents();
+ frameView->endDeferredRepaints();
+ }
RenderWidget::resumeWidgetHierarchyUpdates();
resumePostAttachCallbacks();
- m_inStyleRecalc = false;
// If we wanted to call implicitClose() during recalcStyle, do so now that we're finished.
if (m_closeAfterStyleRecalc) {
@@ -1781,7 +1727,7 @@ void Document::attach()
RenderObject* render = renderer();
setRenderer(0);
- ContainerNode::attach();
+ TreeScope::attach();
setRenderer(render);
}
@@ -1793,7 +1739,13 @@ void Document::detach()
clearAXObjectCache();
stopActiveDOMObjects();
-
+ m_eventQueue->cancelQueuedEvents();
+
+#if ENABLE(REQUEST_ANIMATION_FRAME)
+ // FIXME: consider using ActiveDOMObject.
+ m_scriptedAnimationController = 0;
+#endif
+
RenderObject* render = renderer();
// Send out documentWillBecomeInactive() notifications to registered elements,
@@ -1822,7 +1774,7 @@ void Document::detach()
m_focusedNode = 0;
m_activeNode = 0;
- ContainerNode::detach();
+ TreeScope::detach();
unscheduleStyleRecalc();
@@ -2054,11 +2006,21 @@ HTMLElement* Document::body() const
void Document::setBody(PassRefPtr<HTMLElement> newBody, ExceptionCode& ec)
{
- if (!newBody || !documentElement()) {
+ ec = 0;
+
+ if (!newBody || !documentElement() || !newBody->hasTagName(bodyTag)) {
ec = HIERARCHY_REQUEST_ERR;
return;
}
+ if (newBody->document() && newBody->document() != this) {
+ RefPtr<Node> node = importNode(newBody.get(), true, ec);
+ if (ec)
+ return;
+
+ newBody = toHTMLElement(node.get());
+ }
+
HTMLElement* b = body();
if (!b)
documentElement()->appendChild(newBody, ec);
@@ -2707,7 +2669,8 @@ void Document::processHttpEquiv(const String& equiv, const String& content)
frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String());
}
}
- }
+ } else if (equalIgnoringCase(equiv, "x-webkit-csp"))
+ contentSecurityPolicy()->didReceiveHeader(content);
}
// Though isspace() considers \t and \v to be whitespace, Win IE doesn't.
@@ -2766,9 +2729,9 @@ void Document::processArguments(const String& features, void* data, ArgumentsCal
#ifdef ANDROID_META_SUPPORT
if (frame())
frame()->settings()->setMetadataSettings(keyString, valueString);
-#else
- callback(keyString, valueString, this, data);
#endif
+ if (callback && data)
+ callback(keyString, valueString, this, data);
}
}
@@ -2803,7 +2766,7 @@ MouseEventWithHitTestResults Document::prepareMouseEvent(const HitTestRequest& r
}
// DOM Section 1.1.1
-bool Document::childTypeAllowed(NodeType type)
+bool Document::childTypeAllowed(NodeType type) const
{
switch (type) {
case ATTRIBUTE_NODE:
@@ -3823,7 +3786,9 @@ String Document::lastModified() const
DateComponents date;
bool foundDate = false;
if (m_frame) {
- String httpLastModified = m_documentLoader->response().httpHeaderField("Last-Modified");
+ String httpLastModified;
+ if (DocumentLoader* documentLoader = loader())
+ httpLastModified = documentLoader->response().httpHeaderField("Last-Modified");
if (!httpLastModified.isEmpty()) {
date.setMillisecondsSinceEpochForDateTime(parseDate(httpLastModified));
foundDate = true;
@@ -3939,33 +3904,6 @@ bool Document::parseQualifiedName(const String& qualifiedName, String& prefix, S
return true;
}
-void Document::addImageMap(HTMLMapElement* imageMap)
-{
- AtomicStringImpl* name = imageMap->getName().impl();
- if (!name)
- return;
- m_imageMapsByName.add(name, imageMap);
-}
-
-void Document::removeImageMap(HTMLMapElement* imageMap)
-{
- AtomicStringImpl* name = imageMap->getName().impl();
- if (!name)
- return;
- m_imageMapsByName.remove(name, imageMap);
-}
-
-HTMLMapElement* Document::getImageMap(const String& url) const
-{
- if (url.isNull())
- return 0;
- size_t hashPos = url.find('#');
- String name = (hashPos == notFound ? url : url.substring(hashPos + 1)).impl();
- if (isHTMLDocument())
- return static_cast<HTMLMapElement*>(m_imageMapsByName.getElementByLowercasedMapName(AtomicString(name.lower()).impl(), this));
- return static_cast<HTMLMapElement*>(m_imageMapsByName.getElementByMapName(AtomicString(name).impl(), this));
-}
-
void Document::setDecoder(PassRefPtr<TextResourceDecoder> decoder)
{
m_decoder = decoder;
@@ -3994,7 +3932,7 @@ void Document::setInPageCache(bool flag)
ASSERT(!m_savedRenderer);
m_savedRenderer = renderer();
if (FrameView* v = view())
- v->resetScrollbars();
+ v->resetScrollbarsAndClearContentsSize();
m_styleRecalcTimer.stop();
} else {
ASSERT(!renderer() || renderer() == m_savedRenderer);
@@ -4331,7 +4269,7 @@ void Document::finishedParsing()
if (!m_documentTiming.domContentLoadedEventEnd)
m_documentTiming.domContentLoadedEventEnd = currentTime();
- if (Frame* f = frame()) {
+ if (RefPtr<Frame> f = frame()) {
// FrameLoader::finishedParsing() might end up calling Document::implicitClose() if all
// resource loads are complete. HTMLObjectElements can start loading their resources from
// post attach callbacks triggered by recalcStyle(). This means if we parse out an <object>
@@ -4343,7 +4281,7 @@ void Document::finishedParsing()
f->loader()->finishedParsing();
- InspectorInstrumentation::domContentLoadedEventFired(f, url());
+ InspectorInstrumentation::domContentLoadedEventFired(f.get(), url());
}
}
@@ -4486,7 +4424,7 @@ void FormElementKey::deref() const
unsigned FormElementKeyHash::hash(const FormElementKey& key)
{
- return WTF::StringHasher::createBlobHash<sizeof(FormElementKey)>(&key);
+ return StringHasher::hashMemory<sizeof(FormElementKey)>(&key);
}
void Document::setIconURL(const String& iconURL, const String& type)
@@ -4551,14 +4489,16 @@ void Document::initSecurityContext()
// loading URL with a fresh content security policy.
m_cookieURL = m_url;
ScriptExecutionContext::setSecurityOrigin(SecurityOrigin::create(m_url, m_frame->loader()->sandboxFlags()));
- m_contentSecurityPolicy = ContentSecurityPolicy::create();
+ m_contentSecurityPolicy = ContentSecurityPolicy::create(securityOrigin());
if (SecurityOrigin::allowSubstituteDataAccessToLocal()) {
// If this document was loaded with substituteData, then the document can
// load local resources. See https://bugs.webkit.org/show_bug.cgi?id=16756
// and https://bugs.webkit.org/show_bug.cgi?id=19760 for further
// discussion.
- if (m_documentLoader->substituteData().isValid())
+
+ DocumentLoader* documentLoader = loader();
+ if (documentLoader && documentLoader->substituteData().isValid())
securityOrigin()->grantLoadLocalResources();
}
@@ -4639,7 +4579,9 @@ void Document::updateURLForPushOrReplaceState(const KURL& url)
setURL(url);
f->loader()->setOutgoingReferrer(url);
- m_documentLoader->replaceRequestURLForSameDocumentNavigation(url);
+
+ if (DocumentLoader* documentLoader = loader())
+ documentLoader->replaceRequestURLForSameDocumentNavigation(url);
}
void Document::statePopped(SerializedScriptValue* stateObject)
@@ -4780,59 +4722,22 @@ public:
OwnPtr<ScriptExecutionContext::Task> task;
};
-void Document::didReceiveTask(void* untypedContext)
+static void performTask(void* ctx)
{
ASSERT(isMainThread());
- OwnPtr<PerformTaskContext> context = adoptPtr(static_cast<PerformTaskContext*>(untypedContext));
+ PerformTaskContext* context = reinterpret_cast<PerformTaskContext*>(ctx);
ASSERT(context);
- Document* document = context->documentReference->document();
- if (!document)
- return;
-
- Page* page = document->page();
- if ((page && page->defersLoading()) || !document->m_pendingTasks.isEmpty()) {
- document->m_pendingTasks.append(context->task.release());
- return;
- }
+ if (Document* document = context->documentReference->document())
+ context->task->performTask(document);
- context->task->performTask(document);
+ delete context;
}
void Document::postTask(PassOwnPtr<Task> task)
{
- callOnMainThread(didReceiveTask, new PerformTaskContext(m_weakReference, task));
-}
-
-void Document::pendingTasksTimerFired(Timer<Document>*)
-{
- while (!m_pendingTasks.isEmpty()) {
- OwnPtr<Task> task = m_pendingTasks[0].release();
- m_pendingTasks.remove(0);
- task->performTask(this);
- }
-}
-
-void Document::suspendScheduledTasks()
-{
- suspendScriptedAnimationControllerCallbacks();
- suspendActiveDOMObjects(ActiveDOMObject::WillShowDialog);
- asyncScriptRunner()->suspend();
- m_pendingTasksTimer.stop();
- if (m_parser)
- m_parser->suspendScheduledTasks();
-}
-
-void Document::resumeScheduledTasks()
-{
- if (m_parser)
- m_parser->resumeScheduledTasks();
- if (!m_pendingTasks.isEmpty())
- m_pendingTasksTimer.startOneShot(0);
- asyncScriptRunner()->resume();
- resumeActiveDOMObjects();
- resumeScriptedAnimationControllerCallbacks();
+ callOnMainThread(performTask, new PerformTaskContext(m_weakReference, task));
}
void Document::suspendScriptedAnimationControllerCallbacks()
@@ -4851,29 +4756,6 @@ void Document::resumeScriptedAnimationControllerCallbacks()
#endif
}
-Element* Document::findAnchor(const String& name)
-{
- if (name.isEmpty())
- return 0;
- if (Element* element = getElementById(name))
- return element;
- for (Node* node = this; node; node = node->traverseNextNode()) {
- if (node->hasTagName(aTag)) {
- HTMLAnchorElement* anchor = static_cast<HTMLAnchorElement*>(node);
- if (inQuirksMode()) {
- // Quirks mode, case insensitive comparison of names.
- if (equalIgnoringCase(anchor->name(), name))
- return anchor;
- } else {
- // Strict mode, names need to match exactly.
- if (anchor->name() == name)
- return anchor;
- }
- }
- }
- return 0;
-}
-
String Document::displayStringModifiedByEncoding(const String& str) const
{
if (m_decoder)
@@ -4947,6 +4829,20 @@ bool Document::isXHTMLMPDocument() const
#endif
#if ENABLE(FULLSCREEN_API)
+bool Document::fullScreenIsAllowedForElement(Element* element) const
+{
+ ASSERT(element);
+ while (HTMLFrameOwnerElement* ownerElement = element->document()->ownerElement()) {
+ if (!ownerElement->hasTagName(frameTag) && !ownerElement->hasTagName(iframeTag))
+ continue;
+
+ if (!static_cast<HTMLFrameElementBase*>(ownerElement)->allowFullScreen())
+ return false;
+ element = ownerElement;
+ }
+ return true;
+}
+
void Document::webkitRequestFullScreenForElement(Element* element, unsigned short flags)
{
if (!page() || !page()->settings()->fullScreenEnabled())
@@ -4955,7 +4851,13 @@ void Document::webkitRequestFullScreenForElement(Element* element, unsigned shor
if (!element)
element = documentElement();
- if (!page()->chrome()->client()->supportsFullScreenForElement(element))
+ if (!fullScreenIsAllowedForElement(element))
+ return;
+
+ if (!ScriptController::processingUserGesture())
+ return;
+
+ if (!page()->chrome()->client()->supportsFullScreenForElement(element, flags & Element::ALLOW_KEYBOARD_INPUT))
return;
m_areKeysEnabledInFullScreen = flags & Element::ALLOW_KEYBOARD_INPUT;
@@ -4976,35 +4878,48 @@ void Document::webkitWillEnterFullScreenForElement(Element* element)
ASSERT(page() && page()->settings()->fullScreenEnabled());
m_fullScreenElement = element;
- m_isFullScreen = true;
if (m_fullScreenElement != documentElement())
m_fullScreenElement->detach();
recalcStyle(Force);
- if (m_fullScreenRenderer)
+ if (m_fullScreenRenderer) {
m_fullScreenRenderer->setAnimating(true);
+#if USE(ACCELERATED_COMPOSITING)
+ view()->updateCompositingLayers();
+ if (m_fullScreenRenderer->layer()->isComposited())
+ page()->chrome()->client()->setRootFullScreenLayer(m_fullScreenRenderer->layer()->backing()->graphicsLayer());
+#endif
+ }
}
void Document::webkitDidEnterFullScreenForElement(Element*)
{
- if (m_fullScreenRenderer)
+ if (m_fullScreenRenderer) {
m_fullScreenRenderer->setAnimating(false);
+#if USE(ACCELERATED_COMPOSITING)
+ view()->updateCompositingLayers();
+ page()->chrome()->client()->setRootFullScreenLayer(0);
+#endif
+ }
m_fullScreenChangeDelayTimer.startOneShot(0);
}
void Document::webkitWillExitFullScreenForElement(Element*)
{
- if (m_fullScreenRenderer)
+ if (m_fullScreenRenderer) {
m_fullScreenRenderer->setAnimating(true);
-
- recalcStyle(Force);
+#if USE(ACCELERATED_COMPOSITING)
+ view()->updateCompositingLayers();
+ if (m_fullScreenRenderer->layer()->isComposited())
+ page()->chrome()->client()->setRootFullScreenLayer(m_fullScreenRenderer->layer()->backing()->graphicsLayer());
+#endif
+ }
}
void Document::webkitDidExitFullScreenForElement(Element*)
{
- m_isFullScreen = false;
m_areKeysEnabledInFullScreen = false;
if (m_fullScreenRenderer)
@@ -5012,8 +4927,12 @@ void Document::webkitDidExitFullScreenForElement(Element*)
if (m_fullScreenElement != documentElement())
m_fullScreenElement->detach();
-
+
+ m_fullScreenElement = 0;
setFullScreenRenderer(0);
+#if USE(ACCELERATED_COMPOSITING)
+ page()->chrome()->client()->setRootFullScreenLayer(0);
+#endif
recalcStyle(Force);
m_fullScreenChangeDelayTimer.startOneShot(0);
@@ -5021,6 +4940,11 @@ void Document::webkitDidExitFullScreenForElement(Element*)
void Document::setFullScreenRenderer(RenderFullScreen* renderer)
{
+ if (renderer == m_fullScreenRenderer)
+ return;
+
+ if (m_fullScreenRenderer)
+ m_fullScreenRenderer->destroy();
m_fullScreenRenderer = renderer;
// This notification can come in after the page has been destroyed.
@@ -5041,6 +4965,7 @@ void Document::setFullScreenRendererSize(const IntSize& size)
newStyle->setTop(Length(0, WebCore::Fixed));
newStyle->setLeft(Length(0, WebCore::Fixed));
m_fullScreenRenderer->setStyle(newStyle);
+ updateLayout();
}
}
@@ -5122,34 +5047,19 @@ PassRefPtr<TouchList> Document::createTouchList(ExceptionCode&) const
}
#endif
-static bool hasHeadSibling(const Document* document)
+DocumentLoader* Document::loader() const
{
- Node* de = document->documentElement();
- if (!de)
- return false;
-
- for (Node* i = de->firstChild(); i; i = i->nextSibling()) {
- // A child of the document element which is rather than <head> is
- // typically visible and FOUC safe. So we return true here.
- if (!i->hasTagName(headTag))
- return true;
- }
-
- return false;
-}
-
-bool Document::mayCauseFlashOfUnstyledContent() const
-{
- // Some kind of FOUC is caused by a repaint request before page's <body> arrival
- // because page authors often give background styles to <body>, not to <html>.
- // (And these styles are unavailable before <style> or <link> is given.)
- // This functions is used for checking such possibility of FOUCs.
- // Note that the implementation considers only empty or <head> only contents as a FOUC cause
- // rather than missing <body>, because non-HTML document like SVG and arbitrary XML from foreign namespace
- // should be painted even if there is no <body>.
- if (didLayoutWithPendingStylesheets())
- return true;
- return !hasHeadSibling(this);
+ if (!m_frame)
+ return 0;
+
+ DocumentLoader* loader = m_frame->loader()->activeDocumentLoader();
+ if (!loader)
+ return 0;
+
+ if (m_frame->document() != this)
+ return 0;
+
+ return loader;
}
} // namespace WebCore
diff --git a/Source/WebCore/dom/Document.h b/Source/WebCore/dom/Document.h
index ae9b24e..7478e6c 100644
--- a/Source/WebCore/dom/Document.h
+++ b/Source/WebCore/dom/Document.h
@@ -31,40 +31,35 @@
#include "CollectionCache.h"
#include "CollectionType.h"
#include "Color.h"
-#include "ContainerNode.h"
-#include "ContentSecurityPolicy.h"
#include "DOMTimeStamp.h"
-#include "DocumentOrderedMap.h"
#include "DocumentTiming.h"
#include "QualifiedName.h"
#include "ScriptExecutionContext.h"
+#include "StringWithDirection.h"
#include "Timer.h"
+#include "TreeScope.h"
#include "ViewportArguments.h"
#include <wtf/FixedArray.h>
#include <wtf/OwnPtr.h>
#include <wtf/PassOwnPtr.h>
#include <wtf/PassRefPtr.h>
-#if USE(JSC)
-#include <runtime/WeakGCMap.h>
-#endif
-
namespace WebCore {
-class AsyncScriptRunner;
-class Attr;
class AXObjectCache;
+class Attr;
class CDATASection;
+class CSSPrimitiveValueCache;
+class CSSStyleDeclaration;
+class CSSStyleSelector;
+class CSSStyleSheet;
class CachedCSSStyleSheet;
class CachedResourceLoader;
class CachedScript;
class CanvasRenderingContext;
class CharacterData;
-class CSSPrimitiveValueCache;
-class CSSStyleDeclaration;
-class CSSStyleSelector;
-class CSSStyleSheet;
class Comment;
+class ContentSecurityPolicy;
class DOMImplementation;
class DOMSelection;
class DOMWindow;
@@ -115,6 +110,7 @@ class RenderView;
class RenderFullScreen;
class ScriptableDocumentParser;
class ScriptElementData;
+class ScriptRunner;
class SecurityOrigin;
class SerializedScriptValue;
class SegmentedString;
@@ -205,7 +201,7 @@ enum PageshowEventPersistence {
enum StyleSelectorUpdateFlag { RecalcStyleImmediately, DeferRecalcStyle };
-class Document : public ContainerNode, public ScriptExecutionContext {
+class Document : public TreeScope, public ScriptExecutionContext {
public:
static PassRefPtr<Document> create(Frame* frame, const KURL& url)
{
@@ -219,25 +215,25 @@ public:
MediaQueryMatcher* mediaQueryMatcher();
- using ContainerNode::ref;
- using ContainerNode::deref;
+ using TreeScope::ref;
+ using TreeScope::deref;
- // Nodes belonging to this document hold "self-only" references -
+ // Nodes belonging to this document hold guard 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()
+ // pointer without introducing reference cycles.
+ void guardRef()
{
ASSERT(!m_deletionHasBegun);
- ++m_selfOnlyRefCount;
+ ++m_guardRefCount;
}
- void selfOnlyDeref()
+
+ void guardDeref()
{
ASSERT(!m_deletionHasBegun);
- --m_selfOnlyRefCount;
- if (!m_selfOnlyRefCount && !refCount()) {
+ --m_guardRefCount;
+ if (!m_guardRefCount && !refCount()) {
#ifndef NDEBUG
m_deletionHasBegun = true;
#endif
@@ -245,6 +241,10 @@ public:
}
}
+ virtual void removedLastRef();
+
+ Element* getElementById(const AtomicString& id) const;
+
// DOM methods & attributes for Document
DEFINE_ATTRIBUTE_EVENT_LISTENER(abort);
@@ -259,8 +259,6 @@ public:
DEFINE_ATTRIBUTE_EVENT_LISTENER(dragstart);
DEFINE_ATTRIBUTE_EVENT_LISTENER(drag);
DEFINE_ATTRIBUTE_EVENT_LISTENER(dragend);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(formchange);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(forminput);
DEFINE_ATTRIBUTE_EVENT_LISTENER(input);
DEFINE_ATTRIBUTE_EVENT_LISTENER(invalid);
DEFINE_ATTRIBUTE_EVENT_LISTENER(keydown);
@@ -328,9 +326,6 @@ public:
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);
- Element* getElementById(const AtomicString&) const;
- bool hasElementWithId(AtomicStringImpl* id) const;
- bool containsMultipleElementsWithId(const AtomicString& id) const;
/**
* Retrieve all nodes that intersect a rect in the window's document, until it is fully enclosed by
@@ -394,13 +389,6 @@ public:
PassRefPtr<HTMLAllCollection> all();
- // Find first anchor with the given name.
- // First searches for an element with the given ID, but if that fails, then looks
- // for an anchor with the given name. ID matching is always case sensitive, but
- // Anchor name matching is case sensitive in strict mode and not case sensitive in
- // quirks mode for historical compatibility reasons.
- Element* findAnchor(const String& name);
-
CollectionCache* collectionInfo(CollectionType type)
{
ASSERT(type >= FirstUnnamedDocumentCachedType);
@@ -451,8 +439,6 @@ public:
return m_styleSelector.get();
}
- Element* getElementByAccessKey(const String& key) const;
-
/**
* Updates the pending sheet count and then calls updateStyleSelector.
*/
@@ -567,8 +553,7 @@ public:
void setVisuallyOrdered();
bool visuallyOrdered() const { return m_visuallyOrdered; }
- void setDocumentLoader(DocumentLoader* documentLoader) { m_documentLoader = documentLoader; }
- DocumentLoader* loader() const { return m_documentLoader; }
+ DocumentLoader* loader() const;
void open(Document* ownerDocument = 0);
void implicitOpen();
@@ -808,19 +793,21 @@ public:
void processViewport(const String& features);
#ifdef ANDROID_META_SUPPORT
- /**
- * Handles viewport like <meta name = "viewport" content = "width = device-width">
- * or format-detection like <meta name = "format-detection" content = "telephone=no">
- */
- void processMetadataSettings(const String& content);
+ /**
+ * Handles format-detection like <meta name = "format-detection" content = "telephone=no">
+ */
+ void processMetadataSettings(const String& content);
#endif
// Returns the owning element in the parent document.
// Returns 0 if this is the top level document.
HTMLFrameOwnerElement* ownerElement() const;
- String title() const { return m_title; }
- void setTitle(const String&, Element* titleElement = 0);
+ // Used by DOM bindings; no direction known.
+ String title() const { return m_title.string(); }
+ void setTitle(const String&);
+
+ void setTitleElement(const StringWithDirection&, Element* titleElement);
void removeTitle(Element* titleElement);
String cookie(ExceptionCode&) const;
@@ -871,13 +858,6 @@ public:
// Checks to make sure prefix and namespace do not conflict (per DOM Core 3)
static bool hasPrefixNamespaceMismatch(const QualifiedName&);
- 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() const;
void setBody(PassRefPtr<HTMLElement>, ExceptionCode&);
@@ -908,7 +888,7 @@ public:
int docID() const { return m_docID; }
- AsyncScriptRunner* asyncScriptRunner() { return m_asyncScriptRunner.get(); }
+ ScriptRunner* scriptRunner() { return m_scriptRunner.get(); }
#if ENABLE(XSLT)
void applyXSLTransform(ProcessingInstruction* pi);
@@ -919,8 +899,8 @@ public:
TransformSource* transformSource() const { return m_transformSource.get(); }
#endif
- void incDOMTreeVersion() { ++m_domTreeVersion; }
- unsigned domTreeVersion() const { return m_domTreeVersion; }
+ void incDOMTreeVersion() { m_domTreeVersion = ++s_globalTreeVersion; }
+ uint64_t domTreeVersion() const { return m_domTreeVersion; }
#ifdef ANDROID_STYLE_VERSION
void incStyleVersion() { ++m_styleVersion; }
@@ -955,10 +935,6 @@ public:
void setUseSecureKeyboardEntryWhenActive(bool);
bool useSecureKeyboardEntryWhenActive() const;
- void addNodeListCache() { ++m_numNodeListCaches; }
- void removeNodeListCache() { ASSERT(m_numNodeListCaches > 0); --m_numNodeListCaches; }
- bool hasNodeListCaches() const { return m_numNodeListCaches; }
-
void updateFocusAppearanceSoon(bool restorePreviousSelection);
void cancelFocusAppearanceUpdate();
@@ -978,16 +954,6 @@ public:
virtual void suspendScriptedAnimationControllerCallbacks();
virtual void resumeScriptedAnimationControllerCallbacks();
-#if USE(JSC)
- typedef JSC::WeakGCMap<WebCore::Node*, JSNode> JSWrapperCache;
- typedef HashMap<DOMWrapperWorld*, JSWrapperCache*> JSWrapperCacheMap;
- JSWrapperCacheMap& wrapperCacheMap() { return m_wrapperCacheMap; }
- JSWrapperCache* getWrapperCache(DOMWrapperWorld* world);
- JSWrapperCache* createWrapperCache(DOMWrapperWorld*);
- void destroyWrapperCache(DOMWrapperWorld*);
- void destroyAllWrapperCaches();
-#endif
-
virtual void finishedParsing();
bool inPageCache() const { return m_inPageCache; }
@@ -1058,7 +1024,7 @@ public:
#endif
virtual bool isContextThread() const;
- virtual bool isJSExecutionTerminated() const { return false; }
+ virtual bool isJSExecutionForbidden() const { return false; }
void setUsingGeolocation(bool f) { m_usingGeolocation = f; }
bool usingGeolocation() const { return m_usingGeolocation; };
@@ -1088,8 +1054,8 @@ public:
const QualifiedName& idAttributeName() const { return m_idAttributeName; }
#if ENABLE(FULLSCREEN_API)
- bool webkitIsFullScreen() const { return m_isFullScreen; }
- bool webkitFullScreenKeyboardInputAllowed() const { return m_isFullScreen && m_areKeysEnabledInFullScreen; }
+ bool webkitIsFullScreen() const { return m_fullScreenElement.get(); }
+ bool webkitFullScreenKeyboardInputAllowed() const { return m_fullScreenElement.get() && m_areKeysEnabledInFullScreen; }
Element* webkitCurrentFullScreenElement() const { return m_fullScreenElement.get(); }
void webkitRequestFullScreenForElement(Element*, unsigned short flags);
void webkitCancelFullScreen();
@@ -1106,6 +1072,7 @@ public:
void setFullScreenRendererBackgroundColor(Color);
void fullScreenChangeDelayTimerFired(Timer<Document>*);
+ bool fullScreenIsAllowedForElement(Element*) const;
#endif
// Used to allow element that loads data without going through a FrameLoader to delay the 'load' event.
@@ -1126,8 +1093,6 @@ public:
void serviceScriptedAnimations(DOMTimeStamp);
#endif
- bool mayCauseFlashOfUnstyledContent() const;
-
virtual EventTarget* errorEventTarget();
virtual void logExceptionToConsole(const String& errorMessage, int lineNumber, const String& sourceURL, PassRefPtr<ScriptCallStack>);
@@ -1135,9 +1100,6 @@ public:
ContentSecurityPolicy* contentSecurityPolicy() { return m_contentSecurityPolicy.get(); }
- void suspendScheduledTasks();
- void resumeScheduledTasks();
-
protected:
Document(Frame*, const KURL&, bool isXHTML, bool isHTML);
@@ -1153,13 +1115,12 @@ private:
void processArguments(const String& features, void* data, ArgumentsCallback);
virtual bool isDocument() const { return true; }
- virtual void removedLastRef();
virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
virtual String nodeName() const;
virtual NodeType nodeType() const;
- virtual bool childTypeAllowed(NodeType);
+ virtual bool childTypeAllowed(NodeType) const;
virtual PassRefPtr<Node> cloneNode(bool deep);
virtual bool canReplaceChild(Node* newChild, Node* oldChild);
@@ -1173,7 +1134,7 @@ private:
String encoding() const;
- void updateTitle();
+ void updateTitle(const StringWithDirection&);
void updateFocusAppearanceTimerFired(Timer<Document>*);
void updateBaseURL();
@@ -1185,9 +1146,7 @@ private:
void loadEventDelayTimerFired(Timer<Document>*);
- void pendingTasksTimerFired(Timer<Document>*);
-
- static void didReceiveTask(void*);
+ int m_guardRefCount;
OwnPtr<CSSStyleSelector> m_styleSelector;
bool m_didCalculateStyleSelector;
@@ -1196,7 +1155,6 @@ private:
mutable RefPtr<CSSPrimitiveValueCache> m_cssPrimitiveValueCache;
Frame* m_frame;
- DocumentLoader* m_documentLoader;
OwnPtr<CachedResourceLoader> m_cachedResourceLoader;
RefPtr<DocumentParser> m_parser;
bool m_wellFormed;
@@ -1258,7 +1216,8 @@ private:
RefPtr<Node> m_activeNode;
mutable RefPtr<Element> m_documentElement;
- unsigned m_domTreeVersion;
+ uint64_t m_domTreeVersion;
+ static uint64_t s_globalTreeVersion;
#ifdef ANDROID_STYLE_VERSION
unsigned m_styleVersion;
#endif
@@ -1316,8 +1275,8 @@ private:
// http://www.whatwg.org/specs/web-apps/current-work/#ignore-destructive-writes-counter
unsigned m_ignoreDestructiveWriteCount;
- String m_title;
- String m_rawTitle;
+ StringWithDirection m_title;
+ StringWithDirection m_rawTitle;
bool m_titleSetExplicitly;
RefPtr<Element> m_titleElement;
@@ -1341,15 +1300,13 @@ private:
// points during the lifetime of the Document.
int m_extraLayoutDelay;
- OwnPtr<AsyncScriptRunner> m_asyncScriptRunner;
+ OwnPtr<ScriptRunner> m_scriptRunner;
#if ENABLE(XSLT)
OwnPtr<TransformSource> m_transformSource;
RefPtr<Document> m_transformSourceDocument;
#endif
- DocumentOrderedMap m_imageMapsByName;
-
int m_docID; // A unique document identifier used for things like document-specific mapped attributes.
String m_xmlEncoding;
@@ -1366,14 +1323,8 @@ private:
RefPtr<TextResourceDecoder> m_decoder;
- DocumentOrderedMap m_elementsById;
-
- mutable HashMap<StringImpl*, Element*, CaseFoldingHash> m_elementsByAccessKey;
-
InheritedBool m_designMode;
- int m_selfOnlyRefCount;
-
CheckedRadioButtons m_checkedRadioButtons;
typedef HashMap<AtomicStringImpl*, CollectionCache*> NamedCollectionMap;
@@ -1396,7 +1347,6 @@ private:
HashMap<String, RefPtr<HTMLCanvasElement> > m_cssCanvasElements;
- mutable bool m_accessKeyMapValid;
bool m_createRenderers;
bool m_inPageCache;
String m_iconURL;
@@ -1413,13 +1363,6 @@ private:
bool m_usesViewSourceStyles;
bool m_sawElementsInKnownNamespaces;
- unsigned m_numNodeListCaches;
-
-#if USE(JSC)
- JSWrapperCacheMap m_wrapperCacheMap;
- JSWrapperCache* m_normalWorldWrapperCache;
-#endif
-
bool m_usingGeolocation;
RefPtr<EventQueue> m_eventQueue;
@@ -1435,7 +1378,6 @@ private:
QualifiedName m_idAttributeName;
#if ENABLE(FULLSCREEN_API)
- bool m_isFullScreen;
bool m_areKeysEnabledInFullScreen;
RefPtr<Element> m_fullScreenElement;
RenderFullScreen* m_fullScreenRenderer;
@@ -1460,28 +1402,15 @@ private:
#endif
RefPtr<ContentSecurityPolicy> m_contentSecurityPolicy;
-
- Timer<Document> m_pendingTasksTimer;
- Vector<OwnPtr<Task> > m_pendingTasks;
};
-inline bool Document::hasElementWithId(AtomicStringImpl* id) const
-{
- ASSERT(id);
- return m_elementsById.contains(id);
-}
+// Put these methods here, because they require the Document definition, but we really want to inline them.
-inline bool Document::containsMultipleElementsWithId(const AtomicString& id) const
-{
- return m_elementsById.containsMultiple(id.impl());
-}
-
inline bool Node::isDocumentNode() const
{
return this == m_document;
}
-// here because it uses a Document method but we really want to inline it
inline Node::Node(Document* document, ConstructionType type)
: m_document(document)
, m_previous(0)
@@ -1490,7 +1419,7 @@ inline Node::Node(Document* document, ConstructionType type)
, m_nodeFlags(type)
{
if (m_document)
- m_document->selfOnlyRef();
+ m_document->guardRef();
#if !defined(NDEBUG) || (defined(DUMP_NODE_STATISTICS) && DUMP_NODE_STATISTICS)
trackForDebugging();
#endif
diff --git a/Source/WebCore/dom/Document.idl b/Source/WebCore/dom/Document.idl
index 11d6678..cf820ba 100644
--- a/Source/WebCore/dom/Document.idl
+++ b/Source/WebCore/dom/Document.idl
@@ -29,7 +29,7 @@ module core {
// DOM Level 1 Core
readonly attribute DocumentType doctype;
- readonly attribute [V8Custom] DOMImplementation implementation;
+ readonly attribute DOMImplementation implementation;
readonly attribute Element documentElement;
[ReturnsNew] Element createElement(in [ConvertNullToNullString] DOMString tagName)
@@ -266,8 +266,6 @@ module core {
attribute [DontEnum] EventListener ondrop;
attribute [DontEnum] EventListener onerror;
attribute [DontEnum] EventListener onfocus;
- attribute [DontEnum] EventListener onformchange;
- attribute [DontEnum] EventListener onforminput;
attribute [DontEnum] EventListener oninput;
attribute [DontEnum] EventListener oninvalid;
attribute [DontEnum] EventListener onkeydown;
diff --git a/Source/WebCore/dom/DocumentFragment.cpp b/Source/WebCore/dom/DocumentFragment.cpp
index c9c3020..3882c4d 100644
--- a/Source/WebCore/dom/DocumentFragment.cpp
+++ b/Source/WebCore/dom/DocumentFragment.cpp
@@ -31,7 +31,7 @@
namespace WebCore {
-inline DocumentFragment::DocumentFragment(Document* document)
+DocumentFragment::DocumentFragment(Document* document)
: ContainerNode(document)
{
ASSERT(document);
@@ -52,7 +52,7 @@ Node::NodeType DocumentFragment::nodeType() const
return DOCUMENT_FRAGMENT_NODE;
}
-bool DocumentFragment::childTypeAllowed(NodeType type)
+bool DocumentFragment::childTypeAllowed(NodeType type) const
{
switch (type) {
case ELEMENT_NODE:
diff --git a/Source/WebCore/dom/DocumentFragment.h b/Source/WebCore/dom/DocumentFragment.h
index d588b4e..b035a64 100644
--- a/Source/WebCore/dom/DocumentFragment.h
+++ b/Source/WebCore/dom/DocumentFragment.h
@@ -36,13 +36,14 @@ public:
void parseHTML(const String&, Element* contextElement, FragmentScriptingPermission = FragmentScriptingAllowed);
bool parseXML(const String&, Element* contextElement, FragmentScriptingPermission = FragmentScriptingAllowed);
-private:
+protected:
DocumentFragment(Document*);
-
virtual String nodeName() const;
+
+private:
virtual NodeType nodeType() const;
virtual PassRefPtr<Node> cloneNode(bool deep);
- virtual bool childTypeAllowed(NodeType);
+ virtual bool childTypeAllowed(NodeType) const;
};
} //namespace
diff --git a/Source/WebCore/dom/DocumentMarker.h b/Source/WebCore/dom/DocumentMarker.h
index 81112bf..1711a96 100644
--- a/Source/WebCore/dom/DocumentMarker.h
+++ b/Source/WebCore/dom/DocumentMarker.h
@@ -37,9 +37,9 @@ struct DocumentMarker {
Spelling = 1 << 0,
Grammar = 1 << 1,
TextMatch = 1 << 2,
- // Text has been modified by spell correction. On some platforms, this prevents the text
- // to be autocorrected again. On post Snow Leopard Mac OS X, if a Replacement marker contains
- // non-empty description, a reversion UI will be shown.
+ // Text has been modified by spell correction, reversion of spell correction or other type of substitution.
+ // On some platforms, this prevents the text from being autocorrected again. On post Snow Leopard Mac OS X,
+ // if a Replacement marker contains non-empty description, a reversion UI will be shown.
Replacement = 1 << 3,
// Renderer needs to add underline indicating that the text has been modified by spell
// correction. Text with Replacement marker doesn't necessarily has CorrectionIndicator
@@ -49,12 +49,37 @@ struct DocumentMarker {
CorrectionIndicator = 1 << 4,
// Correction suggestion has been offered, but got rejected by user.
RejectedCorrection = 1 << 5,
- // On some platforms, this prevents the text to be spellchecked again.
- SpellCheckingExemption = 1 << 6,
- AllMarkers = Spelling | Grammar | TextMatch | Replacement | CorrectionIndicator | RejectedCorrection | SpellCheckingExemption
+ // Text has been modified by autocorrection. The description of this marker is the original text before autocorrection.
+ Autocorrected = 1 << 6,
+ // On some platforms, this prevents the text from being spellchecked again.
+ SpellCheckingExemption = 1 << 7,
};
+
+ class MarkerTypes {
+ public:
+ // The constructor is intentionally implicit to allow conversion from the bit-wise sum of above types
+ MarkerTypes(unsigned mask) : m_mask(mask) { }
+
+ bool contains(MarkerType type) const { return m_mask & type; }
+ bool intersects(const MarkerTypes& types) const { return (m_mask & types.m_mask); }
+ bool operator==(const MarkerTypes& other) const { return m_mask == other.m_mask; }
+
+ void add(const MarkerTypes& types) { m_mask |= types.m_mask; }
+ void remove(const MarkerTypes& types) { m_mask &= ~types.m_mask; }
+
+ private:
+ unsigned m_mask;
+ };
+
+ class AllMarkers : public MarkerTypes {
+ public:
+ AllMarkers()
+ : MarkerTypes(Spelling | Grammar | TextMatch | Replacement | CorrectionIndicator | RejectedCorrection | Autocorrected | SpellCheckingExemption)
+ {
+ }
+ };
+
MarkerType type;
- typedef unsigned MarkerTypes;
unsigned startOffset;
unsigned endOffset;
String description;
diff --git a/Source/WebCore/dom/DocumentMarkerController.cpp b/Source/WebCore/dom/DocumentMarkerController.cpp
index f646f3c..d97f2af 100644
--- a/Source/WebCore/dom/DocumentMarkerController.cpp
+++ b/Source/WebCore/dom/DocumentMarkerController.cpp
@@ -40,7 +40,7 @@ static IntRect placeholderRectForMarker()
inline bool DocumentMarkerController::possiblyHasMarkers(DocumentMarker::MarkerTypes types)
{
- return m_possiblyExistingMarkerTypes & types;
+ return m_possiblyExistingMarkerTypes.intersects(types);
}
DocumentMarkerController::DocumentMarkerController()
@@ -91,7 +91,7 @@ void DocumentMarkerController::addMarker(Node* node, DocumentMarker newMarker)
if (newMarker.endOffset == newMarker.startOffset)
return;
- m_possiblyExistingMarkerTypes |= newMarker.type;
+ m_possiblyExistingMarkerTypes.add(newMarker.type);
MarkerMapVectorPair* vectorPair = m_markers.get(node);
@@ -152,12 +152,12 @@ void DocumentMarkerController::addMarker(Node* node, DocumentMarker newMarker)
// 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 DocumentMarkerController::copyMarkers(Node* srcNode, unsigned startOffset, int length, Node* dstNode, int delta, DocumentMarker::MarkerType markerType)
+void DocumentMarkerController::copyMarkers(Node* srcNode, unsigned startOffset, int length, Node* dstNode, int delta)
{
if (length <= 0)
return;
- if (!possiblyHasMarkers(markerType))
+ if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
return;
ASSERT(!m_markers.isEmpty());
@@ -178,7 +178,7 @@ void DocumentMarkerController::copyMarkers(Node* srcNode, unsigned startOffset,
break;
// skip marker that is before the specified range or is the wrong type
- if (marker.endOffset < startOffset || (marker.type != markerType && markerType != DocumentMarker::AllMarkers))
+ if (marker.endOffset < startOffset)
continue;
// pin the marker to the specified range and apply the shift delta
@@ -224,7 +224,7 @@ void DocumentMarkerController::removeMarkers(Node* node, unsigned startOffset, i
break;
// skip marker that is wrong type or before target
- if (marker.endOffset <= startOffset || !(marker.type & markerTypes)) {
+ if (marker.endOffset <= startOffset || !markerTypes.contains(marker.type)) {
i++;
continue;
}
@@ -292,7 +292,7 @@ DocumentMarker* DocumentMarkerController::markerContainingPoint(const IntPoint&
DocumentMarker& marker = markers[markerIndex];
// skip marker that is wrong type
- if (marker.type != markerType && markerType != DocumentMarker::AllMarkers)
+ if (marker.type != markerType)
continue;
IntRect& r = rects[markerIndex];
@@ -317,6 +317,35 @@ Vector<DocumentMarker> DocumentMarkerController::markersForNode(Node* node)
return Vector<DocumentMarker>();
}
+Vector<DocumentMarker> DocumentMarkerController::markersInRange(Range* range, DocumentMarker::MarkerType markerType)
+{
+ if (!possiblyHasMarkers(markerType))
+ return Vector<DocumentMarker>();
+
+ Vector<DocumentMarker> foundMarkers;
+
+ Node* startContainer = range->startContainer();
+ ASSERT(startContainer);
+ Node* endContainer = range->endContainer();
+ ASSERT(endContainer);
+
+ Node* pastLastNode = range->pastLastNode();
+ for (Node* node = range->firstNode(); node != pastLastNode; node = node->traverseNextNode()) {
+ Vector<DocumentMarker> markers = markersForNode(node);
+ Vector<DocumentMarker>::const_iterator end = markers.end();
+ for (Vector<DocumentMarker>::const_iterator it = markers.begin(); it != end; ++it) {
+ if (markerType != it->type)
+ continue;
+ if (node == startContainer && it->endOffset <= static_cast<unsigned>(range->startOffset()))
+ continue;
+ if (node == endContainer && it->startOffset >= static_cast<unsigned>(range->endOffset()))
+ continue;
+ foundMarkers.append(*it);
+ }
+ }
+ return foundMarkers;
+}
+
Vector<IntRect> DocumentMarkerController::renderedRectsForMarkers(DocumentMarker::MarkerType markerType)
{
Vector<IntRect> result;
@@ -338,7 +367,7 @@ Vector<IntRect> DocumentMarkerController::renderedRectsForMarkers(DocumentMarker
DocumentMarker marker = markers[markerIndex];
// skip marker that is wrong type
- if (marker.type != markerType && markerType != DocumentMarker::AllMarkers)
+ if (marker.type != markerType)
continue;
IntRect r = rects[markerIndex];
@@ -379,13 +408,13 @@ void DocumentMarkerController::removeMarkers(DocumentMarker::MarkerTypes markerT
removeMarkersFromMarkerMapVectorPair(node, vectorPair, markerTypes);
}
- m_possiblyExistingMarkerTypes &= ~markerTypes;
+ m_possiblyExistingMarkerTypes.remove(markerTypes);
}
// This function may release node and vectorPair.
void DocumentMarkerController::removeMarkersFromMarkerMapVectorPair(Node* node, MarkerMapVectorPair* vectorPair, DocumentMarker::MarkerTypes markerTypes)
{
- if (!~(markerTypes & DocumentMarker::AllMarkers)) {
+ if (markerTypes == DocumentMarker::AllMarkers()) {
delete vectorPair;
m_markers.remove(node);
if (RenderObject* renderer = node->renderer())
@@ -399,7 +428,7 @@ void DocumentMarkerController::removeMarkersFromMarkerMapVectorPair(Node* node,
DocumentMarker marker = markers[i];
// skip nodes that are not of the specified type
- if (!(marker.type & markerTypes)) {
+ if (!markerTypes.contains(marker.type)) {
++i;
continue;
}
@@ -430,9 +459,9 @@ void DocumentMarkerController::removeMarkersFromMarkerMapVectorPair(Node* node,
m_possiblyExistingMarkerTypes = 0;
}
-void DocumentMarkerController::repaintMarkers(DocumentMarker::MarkerType markerType)
+void DocumentMarkerController::repaintMarkers(DocumentMarker::MarkerTypes markerTypes)
{
- if (!possiblyHasMarkers(markerType))
+ if (!possiblyHasMarkers(markerTypes))
return;
ASSERT(!m_markers.isEmpty());
@@ -449,7 +478,7 @@ void DocumentMarkerController::repaintMarkers(DocumentMarker::MarkerType markerT
DocumentMarker marker = markers[i];
// skip nodes that are not of the specified type
- if (marker.type == markerType || markerType == DocumentMarker::AllMarkers) {
+ if (markerTypes.contains(marker.type)) {
nodeNeedsRepaint = true;
break;
}
@@ -503,9 +532,9 @@ void DocumentMarkerController::invalidateRenderedRectsForMarkersInRect(const Int
}
}
-void DocumentMarkerController::shiftMarkers(Node* node, unsigned startOffset, int delta, DocumentMarker::MarkerType markerType)
+void DocumentMarkerController::shiftMarkers(Node* node, unsigned startOffset, int delta)
{
- if (!possiblyHasMarkers(markerType))
+ if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
return;
ASSERT(!m_markers.isEmpty());
@@ -520,7 +549,7 @@ void DocumentMarkerController::shiftMarkers(Node* node, unsigned startOffset, in
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)) {
+ if (marker.startOffset >= startOffset) {
ASSERT((int)marker.startOffset + delta >= 0);
marker.startOffset += delta;
marker.endOffset += delta;
@@ -538,7 +567,7 @@ void DocumentMarkerController::shiftMarkers(Node* node, unsigned startOffset, in
void DocumentMarkerController::setMarkersActive(Range* range, bool active)
{
- if (!possiblyHasMarkers(DocumentMarker::AllMarkers))
+ if (!possiblyHasMarkers(DocumentMarker::AllMarkers()))
return;
ASSERT(!m_markers.isEmpty());
@@ -600,22 +629,13 @@ bool DocumentMarkerController::hasMarkers(Range* range, DocumentMarker::MarkerTy
Vector<DocumentMarker> markers = markersForNode(node);
Vector<DocumentMarker>::const_iterator end = markers.end();
for (Vector<DocumentMarker>::const_iterator it = markers.begin(); it != end; ++it) {
- if (!(markerTypes & it->type))
+ if (!markerTypes.contains(it->type))
continue;
- if (node == startContainer && node == endContainer) {
- // The range spans only one node.
- if (it->endOffset > static_cast<unsigned>(range->startOffset()) && it->startOffset < static_cast<unsigned>(range->endOffset()))
- return true;
- } else {
- if (node == startContainer) {
- if (it->endOffset > static_cast<unsigned>(range->startOffset()))
- return true;
- } else if (node == endContainer) {
- if (it->startOffset < static_cast<unsigned>(range->endOffset()))
- return true;
- } else
- return true;
- }
+ if (node == startContainer && it->endOffset <= static_cast<unsigned>(range->startOffset()))
+ continue;
+ if (node == endContainer && it->startOffset >= static_cast<unsigned>(range->endOffset()))
+ continue;
+ return true;
}
}
return false;
@@ -647,7 +667,7 @@ void DocumentMarkerController::clearDescriptionOnMarkersIntersectingRange(Range*
break;
// skip marker that is wrong type or before target
- if (marker.endOffset <= startOffset || !(marker.type & markerTypes)) {
+ if (marker.endOffset <= startOffset || !markerTypes.contains(marker.type)) {
i++;
continue;
}
diff --git a/Source/WebCore/dom/DocumentMarkerController.h b/Source/WebCore/dom/DocumentMarkerController.h
index 6fa060a..0f34c9f 100644
--- a/Source/WebCore/dom/DocumentMarkerController.h
+++ b/Source/WebCore/dom/DocumentMarkerController.h
@@ -47,28 +47,29 @@ public:
void detach();
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);
- bool hasMarkers(Range*, DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers);
+ void copyMarkers(Node* srcNode, unsigned startOffset, int length, Node* dstNode, int delta);
+ bool hasMarkers(Range*, DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers());
// When a marker partially overlaps with range, if removePartiallyOverlappingMarkers is true, we completely
// remove the marker. If the argument is false, we will adjust the span of the marker so that it retains
// the portion that is outside of the range.
enum RemovePartiallyOverlappingMarkerOrNot { DoNotRemovePartiallyOverlappingMarker, RemovePartiallyOverlappingMarker };
- void removeMarkers(Range*, DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers, RemovePartiallyOverlappingMarkerOrNot = DoNotRemovePartiallyOverlappingMarker);
- void removeMarkers(Node*, unsigned startOffset, int length, DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers, RemovePartiallyOverlappingMarkerOrNot = DoNotRemovePartiallyOverlappingMarker);
+ void removeMarkers(Range*, DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers(), RemovePartiallyOverlappingMarkerOrNot = DoNotRemovePartiallyOverlappingMarker);
+ void removeMarkers(Node*, unsigned startOffset, int length, DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers(), RemovePartiallyOverlappingMarkerOrNot = DoNotRemovePartiallyOverlappingMarker);
- void removeMarkers(DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers);
- void removeMarkers(Node*, DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers);
- void repaintMarkers(DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
+ void removeMarkers(DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers());
+ void removeMarkers(Node*, DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers());
+ void repaintMarkers(DocumentMarker::MarkerTypes = DocumentMarker::AllMarkers());
void setRenderedRectForMarker(Node*, const DocumentMarker&, const IntRect&);
void invalidateRenderedRectsForMarkersInRect(const IntRect&);
- void shiftMarkers(Node*, unsigned startOffset, int delta, DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
+ void shiftMarkers(Node*, unsigned startOffset, int delta);
void setMarkersActive(Range*, bool);
void setMarkersActive(Node*, unsigned startOffset, unsigned endOffset, bool);
- DocumentMarker* markerContainingPoint(const IntPoint&, DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
+ DocumentMarker* markerContainingPoint(const IntPoint&, DocumentMarker::MarkerType);
Vector<DocumentMarker> markersForNode(Node*);
- Vector<IntRect> renderedRectsForMarkers(DocumentMarker::MarkerType = DocumentMarker::AllMarkers);
+ Vector<DocumentMarker> markersInRange(Range*, DocumentMarker::MarkerType);
+ Vector<IntRect> renderedRectsForMarkers(DocumentMarker::MarkerType);
void clearDescriptionOnMarkersIntersectingRange(Range*, DocumentMarker::MarkerTypes);
#ifndef NDEBUG
diff --git a/Source/WebCore/dom/DocumentOrderedMap.cpp b/Source/WebCore/dom/DocumentOrderedMap.cpp
index 787fcf4..47268c4 100644
--- a/Source/WebCore/dom/DocumentOrderedMap.cpp
+++ b/Source/WebCore/dom/DocumentOrderedMap.cpp
@@ -34,6 +34,7 @@
#include "Element.h"
#include "HTMLMapElement.h"
#include "HTMLNames.h"
+#include "TreeScope.h"
namespace WebCore {
@@ -104,7 +105,7 @@ void DocumentOrderedMap::remove(AtomicStringImpl* key, Element* element)
}
template<bool keyMatches(AtomicStringImpl*, Element*)>
-inline Element* DocumentOrderedMap::get(AtomicStringImpl* key, const Document* document) const
+inline Element* DocumentOrderedMap::get(AtomicStringImpl* key, const TreeScope* scope) const
{
ASSERT(key);
@@ -116,7 +117,7 @@ inline Element* DocumentOrderedMap::get(AtomicStringImpl* key, const Document* d
if (m_duplicateCounts.contains(key)) {
// We know there's at least one node that matches; iterate to find the first one.
- for (Node* node = document->firstChild(); node; node = node->traverseNextNode()) {
+ for (Node* node = scope->firstChild(); node; node = node->traverseNextNode()) {
if (!node->isElementNode())
continue;
element = static_cast<Element*>(node);
@@ -132,19 +133,19 @@ inline Element* DocumentOrderedMap::get(AtomicStringImpl* key, const Document* d
return 0;
}
-Element* DocumentOrderedMap::getElementById(AtomicStringImpl* key, const Document* document) const
+Element* DocumentOrderedMap::getElementById(AtomicStringImpl* key, const TreeScope* scope) const
{
- return get<keyMatchesId>(key, document);
+ return get<keyMatchesId>(key, scope);
}
-Element* DocumentOrderedMap::getElementByMapName(AtomicStringImpl* key, const Document* document) const
+Element* DocumentOrderedMap::getElementByMapName(AtomicStringImpl* key, const TreeScope* scope) const
{
- return get<keyMatchesMapName>(key, document);
+ return get<keyMatchesMapName>(key, scope);
}
-Element* DocumentOrderedMap::getElementByLowercasedMapName(AtomicStringImpl* key, const Document* document) const
+Element* DocumentOrderedMap::getElementByLowercasedMapName(AtomicStringImpl* key, const TreeScope* scope) const
{
- return get<keyMatchesLowercasedMapName>(key, document);
+ return get<keyMatchesLowercasedMapName>(key, scope);
}
} // namespace WebCore
diff --git a/Source/WebCore/dom/DocumentOrderedMap.h b/Source/WebCore/dom/DocumentOrderedMap.h
index 58767c6..7d12686 100644
--- a/Source/WebCore/dom/DocumentOrderedMap.h
+++ b/Source/WebCore/dom/DocumentOrderedMap.h
@@ -37,8 +37,8 @@
namespace WebCore {
-class Document;
class Element;
+class TreeScope;
class DocumentOrderedMap {
public:
@@ -49,14 +49,14 @@ public:
bool contains(AtomicStringImpl*) const;
bool containsMultiple(AtomicStringImpl*) const;
// concrete instantiations of the get<>() method template
- Element* getElementById(AtomicStringImpl*, const Document*) const;
- Element* getElementByMapName(AtomicStringImpl*, const Document*) const;
- Element* getElementByLowercasedMapName(AtomicStringImpl*, const Document*) const;
+ Element* getElementById(AtomicStringImpl*, const TreeScope*) const;
+ Element* getElementByMapName(AtomicStringImpl*, const TreeScope*) const;
+ Element* getElementByLowercasedMapName(AtomicStringImpl*, const TreeScope*) const;
void checkConsistency() const;
private:
- template<bool keyMatches(AtomicStringImpl*, Element*)> Element* get(AtomicStringImpl*, const Document*) const;
+ template<bool keyMatches(AtomicStringImpl*, Element*)> Element* get(AtomicStringImpl*, const TreeScope*) const;
typedef HashMap<AtomicStringImpl*, Element*> Map;
diff --git a/Source/WebCore/dom/DynamicNodeList.cpp b/Source/WebCore/dom/DynamicNodeList.cpp
index 3538b60..23664e8 100644
--- a/Source/WebCore/dom/DynamicNodeList.cpp
+++ b/Source/WebCore/dom/DynamicNodeList.cpp
@@ -145,6 +145,11 @@ Node* DynamicNodeList::itemWithName(const AtomicString& elementId) const
return 0;
}
+bool DynamicNodeList::isDynamicNodeList() const
+{
+ return true;
+}
+
void DynamicNodeList::invalidateCache()
{
// This should only be called for node lists that own their own caches.
diff --git a/Source/WebCore/dom/DynamicNodeList.h b/Source/WebCore/dom/DynamicNodeList.h
index db133b7..9c8f3cc 100644
--- a/Source/WebCore/dom/DynamicNodeList.h
+++ b/Source/WebCore/dom/DynamicNodeList.h
@@ -60,6 +60,7 @@ namespace WebCore {
// Other methods (not part of DOM)
void invalidateCache();
+ Node* rootNode() const { return m_rootNode.get(); }
protected:
DynamicNodeList(PassRefPtr<Node> rootNode);
@@ -72,6 +73,7 @@ namespace WebCore {
bool m_ownsCaches;
private:
+ virtual bool isDynamicNodeList() const;
Node* itemForwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const;
Node* itemBackwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const;
};
diff --git a/Source/WebCore/dom/Element.cpp b/Source/WebCore/dom/Element.cpp
index 41c0fb1..eef2419 100644
--- a/Source/WebCore/dom/Element.cpp
+++ b/Source/WebCore/dom/Element.cpp
@@ -54,8 +54,11 @@
#include "RenderView.h"
#include "RenderWidget.h"
#include "Settings.h"
+#include "ShadowRoot.h"
#include "TextIterator.h"
+#include "WebKitAnimationList.h"
#include "XMLNames.h"
+#include "htmlediting.h"
#include <wtf/text/CString.h>
#if ENABLE(SVG)
@@ -87,7 +90,13 @@ public:
if (!m_pushedStyleSelector)
return;
+
+ // This tells us that our pushed style selector is in a bad state,
+ // so we should just bail out in that scenario.
ASSERT(m_pushedStyleSelector == m_parent->document()->styleSelector());
+ if (m_pushedStyleSelector != m_parent->document()->styleSelector())
+ return;
+
m_pushedStyleSelector->popParent(m_parent);
}
@@ -541,11 +550,19 @@ PassRefPtr<ClientRectList> Element::getClientRects() const
Vector<FloatQuad> quads;
renderBoxModelObject->absoluteQuads(quads);
+ float pageScale = 1;
+ if (Page* page = document()->page()) {
+ if (Frame* frame = page->mainFrame())
+ pageScale = frame->pageScaleFactor();
+ }
+
if (FrameView* view = document()->view()) {
IntRect visibleContentRect = view->visibleContentRect();
for (size_t i = 0; i < quads.size(); ++i) {
quads[i].move(-visibleContentRect.x(), -visibleContentRect.y());
adjustFloatQuadForAbsoluteZoom(quads[i], renderBoxModelObject);
+ if (pageScale != 1)
+ adjustFloatQuadForPageScale(quads[i], pageScale);
}
}
@@ -585,6 +602,11 @@ PassRefPtr<ClientRect> Element::getBoundingClientRect() const
}
adjustFloatRectForAbsoluteZoom(result, renderer());
+ if (Page* page = document()->page()) {
+ if (Frame* frame = page->mainFrame())
+ adjustFloatRectForPageScale(result, frame->pageScaleFactor());
+ }
+
return ClientRect::create(result);
}
@@ -641,22 +663,20 @@ void Element::setAttribute(const AtomicString& name, const AtomicString& value,
#endif
const AtomicString& localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
-
+ QualifiedName attributeName(nullAtom, localName, nullAtom);
+
// Allocate attribute map if necessary.
Attribute* old = attributes(false)->getAttributeItem(localName, false);
document()->incDOMTreeVersion();
- // FIXME: This check is probably not correct for the case where the document has an id attribute
- // with a non-null namespace, because it will return true if the local name happens to match
- // but the namespace does not.
- if (localName == document()->idAttributeName().localName())
+ if (isIdAttributeName(old ? old->name() : attributeName))
updateId(old ? old->value() : nullAtom, value);
if (old && value.isNull())
m_attributeMap->removeAttribute(old->name());
else if (!old && !value.isNull())
- m_attributeMap->addAttribute(createAttribute(QualifiedName(nullAtom, localName, nullAtom), value));
+ m_attributeMap->addAttribute(createAttribute(attributeName, value));
else if (old && !value.isNull()) {
if (Attr* attrNode = old->attr())
attrNode->setValue(value);
@@ -711,6 +731,8 @@ PassRefPtr<Attribute> Element::createAttribute(const QualifiedName& name, const
void Element::attributeChanged(Attribute* attr, bool)
{
+ if (isIdAttributeName(attr->name()))
+ idAttributeChanged(attr);
recalcStyleIfNeededAfterAttributeChanged(attr);
updateAfterAttributeChanged(attr);
}
@@ -749,6 +771,20 @@ void Element::recalcStyleIfNeededAfterAttributeChanged(Attribute* attr)
setNeedsStyleRecalc();
}
+void Element::idAttributeChanged(Attribute* attr)
+{
+ setHasID(!attr->isNull());
+ if (attributeMap()) {
+ if (attr->isNull())
+ attributeMap()->setIdForStyleResolution(nullAtom);
+ else if (document()->inQuirksMode())
+ attributeMap()->setIdForStyleResolution(attr->value().lower());
+ else
+ attributeMap()->setIdForStyleResolution(attr->value());
+ }
+ setNeedsStyleRecalc();
+}
+
// Returns true is the given attribute is an event handler.
// We consider an event handler any attribute that begins with "on".
// It is a simple solution that has the advantage of not requiring any
@@ -955,13 +991,16 @@ void Element::attach()
createRendererIfNeeded();
StyleSelectorParentPusher parentPusher(this);
- if (firstChild())
- parentPusher.push();
- ContainerNode::attach();
+
if (Node* shadow = shadowRoot()) {
parentPusher.push();
shadow->attach();
}
+
+ if (firstChild())
+ parentPusher.push();
+ ContainerNode::attach();
+
if (hasRareData()) {
ElementRareData* data = rareData();
if (data->needsFocusAppearanceUpdateSoonAfterAttach()) {
@@ -1045,7 +1084,7 @@ void Element::recalcStyle(StyleChange change)
{
// Ref currentStyle in case it would otherwise be deleted when setRenderStyle() is called.
RefPtr<RenderStyle> currentStyle(renderStyle());
- bool hasParentStyle = parentOrHostNode() ? parentOrHostNode()->renderStyle() : false;
+ bool hasParentStyle = parentNodeForRenderingAndStyle() ? parentNodeForRenderingAndStyle()->renderStyle() : false;
bool hasDirectAdjacentRules = currentStyle && currentStyle->childrenAffectedByDirectAdjacentRules();
if ((change > NoChange || needsStyleRecalc())) {
@@ -1132,7 +1171,7 @@ void Element::recalcStyle(StyleChange change)
}
// FIXME: This does not care about sibling combinators. Will be necessary in XBL2 world.
if (Node* shadow = shadowRoot()) {
- if (change >= Inherit || shadow->isTextNode() || shadow->childNeedsStyleRecalc() || shadow->needsStyleRecalc()) {
+ if (change >= Inherit || shadow->childNeedsStyleRecalc() || shadow->needsStyleRecalc()) {
parentPusher.push();
shadow->recalcStyle(change);
}
@@ -1142,28 +1181,24 @@ void Element::recalcStyle(StyleChange change)
clearChildNeedsStyleRecalc();
}
-Node* Element::shadowRoot()
+ContainerNode* Element::shadowRoot() const
{
return hasRareData() ? rareData()->m_shadowRoot : 0;
}
-void Element::setShadowRoot(PassRefPtr<Node> node)
+ContainerNode* Element::ensureShadowRoot()
{
- // FIXME: Because today this is never called from script directly, we don't have to worry
- // about compromising DOM tree integrity (eg. node being a parent of this). However,
- // once we implement XBL2, we will have to add integrity checks here.
- removeShadowRoot();
-
- RefPtr<Node> newRoot = node;
- if (!newRoot)
- return;
+ if (ContainerNode* existingRoot = shadowRoot())
+ return existingRoot;
+ RefPtr<ShadowRoot> newRoot = ShadowRoot::create(document());
ensureRareData()->m_shadowRoot = newRoot.get();
newRoot->setShadowHost(this);
if (inDocument())
newRoot->insertedIntoDocument();
- if (attached() && !newRoot->attached())
+ if (attached())
newRoot->lazyAttach();
+ return newRoot.get();
}
void Element::removeShadowRoot()
@@ -1183,7 +1218,7 @@ void Element::removeShadowRoot()
}
}
-bool Element::childTypeAllowed(NodeType type)
+bool Element::childTypeAllowed(NodeType type) const
{
switch (type) {
case ELEMENT_NODE:
@@ -1199,6 +1234,15 @@ bool Element::childTypeAllowed(NodeType type)
return false;
}
+static void checkForEmptyStyleChange(Element* element, RenderStyle* style)
+{
+ if (!style)
+ return;
+
+ if (style->affectedByEmpty() && (!style->emptyState() || element->hasChildNodes()))
+ element->setNeedsStyleRecalc();
+}
+
static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback,
Node* beforeChange, Node* afterChange, int childCountDelta)
{
@@ -1275,17 +1319,18 @@ static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool fin
e->setNeedsStyleRecalc();
// :empty selector.
- if (style->affectedByEmpty() && (!style->emptyState() || e->hasChildNodes()))
- e->setNeedsStyleRecalc();
+ checkForEmptyStyleChange(e, style);
}
void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
{
ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
- if (!changedByParser)
+ if (changedByParser)
+ checkForEmptyStyleChange(this, renderStyle());
+ else
checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta);
}
-
+
void Element::beginParsingChildren()
{
clearIsParsingChildrenFinished();
@@ -1413,10 +1458,8 @@ PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionCode& ec)
ec = NOT_FOUND_ERR;
return 0;
}
- if (document() != attr->document()) {
- ec = WRONG_DOCUMENT_ERR;
- return 0;
- }
+
+ ASSERT(document() == attr->document());
NamedNodeMap* attrs = attributes(true);
if (!attrs)
@@ -1508,6 +1551,9 @@ CSSStyleDeclaration *Element::style()
void Element::focus(bool restorePreviousSelection)
{
+ if (!inDocument())
+ return;
+
Document* doc = document();
if (doc->focusedNode() == this)
return;
@@ -1558,7 +1604,7 @@ void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
return;
// FIXME: We should restore the previous selection if there is one.
- VisibleSelection newSelection = VisibleSelection(firstPositionInNode(this), DOWNSTREAM);
+ VisibleSelection newSelection = VisibleSelection(firstPositionInOrBeforeNode(this), DOWNSTREAM);
if (frame->selection()->shouldChangeSelection(newSelection)) {
frame->selection()->setSelection(newSelection);
@@ -1891,4 +1937,17 @@ bool Element::isSpellCheckingEnabled() const
return true;
}
+PassRefPtr<WebKitAnimationList> Element::webkitGetAnimations() const
+{
+ if (!renderer())
+ return 0;
+
+ AnimationController* animController = renderer()->animation();
+
+ if (!animController)
+ return 0;
+
+ return animController->animationsForRenderer(renderer());
+}
+
} // namespace WebCore
diff --git a/Source/WebCore/dom/Element.h b/Source/WebCore/dom/Element.h
index 5c54ce4..d269dbe 100644
--- a/Source/WebCore/dom/Element.h
+++ b/Source/WebCore/dom/Element.h
@@ -39,6 +39,7 @@ class DOMStringMap;
class DOMTokenList;
class ElementRareData;
class IntSize;
+class WebKitAnimationList;
enum SpellcheckAttributeState {
SpellcheckAttributeTrue,
@@ -63,8 +64,6 @@ public:
DEFINE_ATTRIBUTE_EVENT_LISTENER(dragstart);
DEFINE_ATTRIBUTE_EVENT_LISTENER(drag);
DEFINE_ATTRIBUTE_EVENT_LISTENER(dragend);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(formchange);
- DEFINE_ATTRIBUTE_EVENT_LISTENER(forminput);
DEFINE_ATTRIBUTE_EVENT_LISTENER(input);
DEFINE_ATTRIBUTE_EVENT_LISTENER(invalid);
DEFINE_ATTRIBUTE_EVENT_LISTENER(keydown);
@@ -230,8 +229,10 @@ public:
virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
virtual void recalcStyle(StyleChange = NoChange);
- Node* shadowRoot();
- void setShadowRoot(PassRefPtr<Node>);
+ ContainerNode* shadowRoot() const;
+ ContainerNode* ensureShadowRoot();
+ void removeShadowRoot();
+
virtual const AtomicString& shadowPseudoId() const;
RenderStyle* computedStyle(PseudoId = NOPSEUDO);
@@ -302,6 +303,10 @@ public:
static bool isMathMLElement() { return false; }
#endif
+#if ENABLE(INPUT_SPEECH)
+ virtual bool isInputFieldSpeechButtonElement() const { return false; }
+#endif
+
virtual bool isFormControlElement() const { return false; }
virtual bool isEnabledFormControl() const { return true; }
virtual bool isReadOnlyFormControl() const { return false; }
@@ -344,6 +349,8 @@ public:
virtual bool isSpellCheckingEnabled() const;
+ PassRefPtr<WebKitAnimationList> webkitGetAnimations() const;
+
protected:
Element(const QualifiedName& tagName, Document* document, ConstructionType type)
: ContainerNode(document, type)
@@ -361,13 +368,15 @@ protected:
// They are separated to allow a different flow of control in StyledElement::attributeChanged().
void recalcStyleIfNeededAfterAttributeChanged(Attribute*);
void updateAfterAttributeChanged(Attribute*);
+
+ void idAttributeChanged(Attribute*);
private:
void scrollByUnits(int units, ScrollGranularity);
virtual void setPrefix(const AtomicString&, ExceptionCode&);
virtual NodeType nodeType() const;
- virtual bool childTypeAllowed(NodeType);
+ virtual bool childTypeAllowed(NodeType) const;
virtual PassRefPtr<Attribute> createAttribute(const QualifiedName&, const AtomicString& value);
@@ -404,7 +413,6 @@ private:
ElementRareData* ensureRareData();
SpellcheckAttributeState spellcheckAttributeState() const;
- void removeShadowRoot();
private:
mutable RefPtr<NamedNodeMap> m_attributeMap;
diff --git a/Source/WebCore/dom/Element.idl b/Source/WebCore/dom/Element.idl
index 652a75b..0e91811 100644
--- a/Source/WebCore/dom/Element.idl
+++ b/Source/WebCore/dom/Element.idl
@@ -96,6 +96,8 @@ module core {
void scrollByLines(in long lines);
void scrollByPages(in long pages);
+ WebKitAnimationList webkitGetAnimations();
+
// HTML 5
NodeList getElementsByClassName(in DOMString name);
@@ -153,8 +155,6 @@ module core {
attribute [DontEnum] EventListener ondrop;
attribute [DontEnum] EventListener onerror;
attribute [DontEnum] EventListener onfocus;
- attribute [DontEnum] EventListener onformchange;
- attribute [DontEnum] EventListener onforminput;
attribute [DontEnum] EventListener oninput;
attribute [DontEnum] EventListener oninvalid;
attribute [DontEnum] EventListener onkeydown;
diff --git a/Source/WebCore/dom/ElementRareData.h b/Source/WebCore/dom/ElementRareData.h
index 818a2c2..14ceef2 100644
--- a/Source/WebCore/dom/ElementRareData.h
+++ b/Source/WebCore/dom/ElementRareData.h
@@ -30,6 +30,8 @@
namespace WebCore {
+class ShadowRoot;
+
class ElementRareData : public NodeRareData {
public:
ElementRareData();
@@ -42,7 +44,7 @@ public:
IntSize m_minimumSizeForResizing;
RefPtr<RenderStyle> m_computedStyle;
- Node* m_shadowRoot;
+ ShadowRoot* m_shadowRoot;
OwnPtr<DatasetDOMStringMap> m_datasetDOMStringMap;
OwnPtr<ClassList> m_classList;
diff --git a/Source/WebCore/dom/Event.cpp b/Source/WebCore/dom/Event.cpp
index 795dace..9cb2778 100644
--- a/Source/WebCore/dom/Event.cpp
+++ b/Source/WebCore/dom/Event.cpp
@@ -22,6 +22,7 @@
#include "config.h"
#include "Event.h"
+#include "EventDispatcher.h"
#include "EventTarget.h"
#include "UserGestureIndicator.h"
@@ -228,6 +229,11 @@ bool Event::isAudioProcessingEvent() const
{
return false;
}
+
+bool Event::isOfflineAudioCompletionEvent() const
+{
+ return false;
+}
#endif
#if ENABLE(INPUT_SPEECH)
@@ -258,7 +264,7 @@ bool Event::fromUserGesture()
// other accepted events
|| type == eventNames().selectEvent || type == eventNames().changeEvent
|| type == eventNames().focusEvent || type == eventNames().blurEvent
- || type == eventNames().submitEvent || type == eventNames().formchangeEvent;
+ || type == eventNames().submitEvent;
}
bool Event::storesResultAsString() const
@@ -272,6 +278,9 @@ void Event::storeResult(const String&)
void Event::setTarget(PassRefPtr<EventTarget> target)
{
+ if (m_target == target)
+ return;
+
m_target = target;
if (m_target)
receivedTarget();
@@ -290,4 +299,18 @@ void Event::setUnderlyingEvent(PassRefPtr<Event> ue)
m_underlyingEvent = ue;
}
+EventDispatchMediator::EventDispatchMediator(PassRefPtr<Event> event)
+ : m_event(event)
+{
+}
+
+EventDispatchMediator::~EventDispatchMediator()
+{
+}
+
+bool EventDispatchMediator::dispatchEvent(EventDispatcher* dispatcher) const
+{
+ return dispatcher->dispatchEvent(m_event.get());
+}
+
} // namespace WebCore
diff --git a/Source/WebCore/dom/Event.h b/Source/WebCore/dom/Event.h
index ba9576b..f6e5586 100644
--- a/Source/WebCore/dom/Event.h
+++ b/Source/WebCore/dom/Event.h
@@ -32,6 +32,7 @@
namespace WebCore {
class EventTarget;
+ class EventDispatcher;
class Event : public RefCounted<Event> {
public:
@@ -130,6 +131,7 @@ namespace WebCore {
#endif
#if ENABLE(WEB_AUDIO)
virtual bool isAudioProcessingEvent() const;
+ virtual bool isOfflineAudioCompletionEvent() const;
#endif
virtual bool isErrorEvent() const;
#if ENABLE(TOUCH_EVENTS)
@@ -165,6 +167,7 @@ namespace WebCore {
virtual Clipboard* clipboard() const { return 0; }
+
protected:
Event();
Event(const AtomicString& type, bool canBubble, bool cancelable);
@@ -191,6 +194,37 @@ namespace WebCore {
RefPtr<Event> m_underlyingEvent;
};
+class EventDispatchMediator {
+public:
+ explicit EventDispatchMediator(PassRefPtr<Event>);
+ virtual ~EventDispatchMediator();
+
+ virtual bool dispatchEvent(EventDispatcher*) const;
+
+protected:
+ EventDispatchMediator();
+
+ Event* event() const;
+ void setEvent(PassRefPtr<Event>);
+
+private:
+ RefPtr<Event> m_event;
+};
+
+inline EventDispatchMediator::EventDispatchMediator()
+{
+}
+
+inline Event* EventDispatchMediator::event() const
+{
+ return m_event.get();
+}
+
+inline void EventDispatchMediator::setEvent(PassRefPtr<Event> event)
+{
+ m_event = event;
+}
+
} // namespace WebCore
#endif // Event_h
diff --git a/Source/WebCore/dom/EventDispatcher.cpp b/Source/WebCore/dom/EventDispatcher.cpp
new file mode 100644
index 0000000..50d4997
--- /dev/null
+++ b/Source/WebCore/dom/EventDispatcher.cpp
@@ -0,0 +1,394 @@
+/*
+ * 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, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ * Copyright (C) 2011 Google 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 "EventDispatcher.h"
+
+#include "Event.h"
+#include "EventContext.h"
+#include "EventTarget.h"
+#include "FrameView.h"
+#include "InspectorInstrumentation.h"
+#include "MouseEvent.h"
+#include "Node.h"
+#include "ScopedEventQueue.h"
+
+#if ENABLE(SVG)
+#include "SVGElementInstance.h"
+#include "SVGNames.h"
+#include "SVGUseElement.h"
+#endif
+
+#include "UIEvent.h"
+#include "UIEventWithKeyState.h"
+#include "WindowEventContext.h"
+
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+static HashSet<Node*>* gNodesDispatchingSimulatedClicks = 0;
+
+bool EventDispatcher::dispatchEvent(Node* node, const EventDispatchMediator& mediator)
+{
+ ASSERT(!eventDispatchForbidden());
+
+ EventDispatcher dispatcher(node);
+ return mediator.dispatchEvent(&dispatcher);
+}
+
+static EventTarget* findElementInstance(Node* referenceNode)
+{
+#if ENABLE(SVG)
+ // Spec: The event handling for the non-exposed tree works as if the referenced element had been textually included
+ // as a deeply cloned child of the 'use' element, except that events are dispatched to the SVGElementInstance objects
+ for (Node* n = referenceNode; n; n = n->parentNode()) {
+ if (!n->isSVGShadowRoot() || !n->isSVGElement())
+ continue;
+
+ Element* shadowTreeParentElement = n->svgShadowHost();
+ ASSERT(shadowTreeParentElement->hasTagName(SVGNames::useTag));
+
+ if (SVGElementInstance* instance = static_cast<SVGUseElement*>(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode))
+ return instance;
+ }
+#else
+ // SVG elements with SVG disabled should not be possible.
+ ASSERT_NOT_REACHED();
+#endif
+
+ return referenceNode;
+}
+
+inline static EventTarget* eventTargetRespectingSVGTargetRules(Node* referenceNode)
+{
+ ASSERT(referenceNode);
+
+ return referenceNode->isSVGElement() ? findElementInstance(referenceNode) : referenceNode;
+}
+
+void EventDispatcher::dispatchScopedEvent(Node* node, PassRefPtr<Event> event)
+{
+ // We need to set the target here because it can go away by the time we actually fire the event.
+ event->setTarget(eventTargetRespectingSVGTargetRules(node));
+
+ ScopedEventQueue::instance()->enqueueEvent(event);
+}
+
+void EventDispatcher::dispatchSimulatedClick(Node* node, PassRefPtr<Event> underlyingEvent, bool sendMouseEvents, bool showPressedLook)
+{
+ if (node->disabled())
+ return;
+
+ EventDispatcher dispatcher(node);
+
+ if (!gNodesDispatchingSimulatedClicks)
+ gNodesDispatchingSimulatedClicks = new HashSet<Node*>;
+ else if (gNodesDispatchingSimulatedClicks->contains(node))
+ return;
+
+ gNodesDispatchingSimulatedClicks->add(node);
+
+ // send mousedown and mouseup before the click, if requested
+ if (sendMouseEvents)
+ dispatcher.dispatchEvent(SimulatedMouseEvent::create(eventNames().mousedownEvent, node->document()->defaultView(), underlyingEvent));
+ node->setActive(true, showPressedLook);
+ if (sendMouseEvents)
+ dispatcher.dispatchEvent(SimulatedMouseEvent::create(eventNames().mouseupEvent, node->document()->defaultView(), underlyingEvent));
+ node->setActive(false);
+
+ // always send click
+ dispatcher.dispatchEvent(SimulatedMouseEvent::create(eventNames().clickEvent, node->document()->defaultView(), underlyingEvent));
+
+ gNodesDispatchingSimulatedClicks->remove(node);
+}
+
+static inline bool isShadowRootOrSVGShadowRoot(const Node* node)
+{
+ return node->isShadowRoot() || node->isSVGShadowRoot();
+}
+
+PassRefPtr<EventTarget> EventDispatcher::adjustToShadowBoundaries(PassRefPtr<Node> relatedTarget, const Vector<Node*> relatedTargetAncestors)
+{
+ Vector<EventContext>::const_iterator lowestCommonBoundary = m_ancestors.end();
+ // Assume divergent boundary is the relatedTarget itself (in other words, related target ancestor chain does not cross any shadow DOM boundaries).
+ Vector<Node*>::const_iterator firstDivergentBoundary = relatedTargetAncestors.begin();
+
+ Vector<EventContext>::const_iterator targetAncestor = m_ancestors.end();
+ // Walk down from the top, looking for lowest common ancestor, also monitoring shadow DOM boundaries.
+ bool diverged = false;
+ for (Vector<Node*>::const_iterator i = relatedTargetAncestors.end() - 1; i >= relatedTargetAncestors.begin(); --i) {
+ if (diverged) {
+ if (isShadowRootOrSVGShadowRoot(*i)) {
+ firstDivergentBoundary = i + 1;
+ break;
+ }
+ continue;
+ }
+
+ if (targetAncestor == m_ancestors.begin()) {
+ diverged = true;
+ continue;
+ }
+
+ targetAncestor--;
+
+ if (isShadowRootOrSVGShadowRoot(*i))
+ lowestCommonBoundary = targetAncestor;
+
+ if ((*i) != (*targetAncestor).node())
+ diverged = true;
+ }
+
+ if (!diverged) {
+ // The relatedTarget is an ancestor or shadowHost of the target.
+ if (m_node->shadowHost() == relatedTarget.get())
+ lowestCommonBoundary = m_ancestors.begin();
+ } else if ((*firstDivergentBoundary) == m_node.get()) {
+ // Since ancestors does not contain target itself, we must account
+ // for the possibility that target is a shadowHost of relatedTarget
+ // and thus serves as the lowestCommonBoundary.
+ // Luckily, in this case the firstDivergentBoundary is target.
+ lowestCommonBoundary = m_ancestors.begin();
+ }
+
+ // Trim ancestors to lowestCommonBoundary to keep events inside of the common shadow DOM subtree.
+ if (lowestCommonBoundary != m_ancestors.end())
+ m_ancestors.shrink(lowestCommonBoundary - m_ancestors.begin());
+ // Set event's related target to the first encountered shadow DOM boundary in the divergent subtree.
+ return firstDivergentBoundary != relatedTargetAncestors.begin() ? *firstDivergentBoundary : relatedTarget;
+}
+
+inline static bool ancestorsCrossShadowBoundaries(const Vector<EventContext>& ancestors)
+{
+ return ancestors.isEmpty() || ancestors.first().node() == ancestors.last().node();
+}
+
+// FIXME: Once https://bugs.webkit.org/show_bug.cgi?id=52963 lands, this should
+// be greatly improved. See https://bugs.webkit.org/show_bug.cgi?id=54025.
+PassRefPtr<EventTarget> EventDispatcher::adjustRelatedTarget(Event* event, PassRefPtr<EventTarget> prpRelatedTarget)
+{
+ if (!prpRelatedTarget)
+ return 0;
+
+ RefPtr<Node> relatedTarget = prpRelatedTarget->toNode();
+ if (!relatedTarget)
+ return 0;
+
+ Node* target = m_node.get();
+ if (!target)
+ return prpRelatedTarget;
+
+ ensureEventAncestors(event);
+
+ // Calculate early if the common boundary is even possible by looking at
+ // ancestors size and if the retargeting has occured (indicating the presence of shadow DOM boundaries).
+ // If there are no boundaries detected, the target and related target can't have a common boundary.
+ bool noCommonBoundary = ancestorsCrossShadowBoundaries(m_ancestors);
+
+ Vector<Node*> relatedTargetAncestors;
+ Node* outermostShadowBoundary = relatedTarget.get();
+ for (Node* n = outermostShadowBoundary; n; n = n->parentOrHostNode()) {
+ if (isShadowRootOrSVGShadowRoot(n))
+ outermostShadowBoundary = n->parentOrHostNode();
+ if (!noCommonBoundary)
+ relatedTargetAncestors.append(n);
+ }
+
+ // Short-circuit the fast case when we know there is no need to calculate a common boundary.
+ if (noCommonBoundary)
+ return outermostShadowBoundary;
+
+ return adjustToShadowBoundaries(relatedTarget.release(), relatedTargetAncestors);
+}
+
+EventDispatcher::EventDispatcher(Node* node)
+ : m_node(node)
+ , m_ancestorsInitialized(false)
+{
+ ASSERT(node);
+ m_view = node->document()->view();
+}
+
+void EventDispatcher::ensureEventAncestors(Event* event)
+{
+ EventDispatchBehavior behavior = determineDispatchBehavior(event);
+
+ if (!m_node->inDocument())
+ return;
+
+ if (m_ancestorsInitialized)
+ return;
+
+ m_ancestorsInitialized = true;
+
+ Node* ancestor = m_node.get();
+ EventTarget* target = eventTargetRespectingSVGTargetRules(ancestor);
+ bool shouldSkipNextAncestor = false;
+ while (true) {
+ bool isSVGShadowRoot = ancestor->isSVGShadowRoot();
+ if (isSVGShadowRoot || ancestor->isShadowRoot()) {
+ if (behavior == StayInsideShadowDOM)
+ return;
+#if ENABLE(SVG)
+ ancestor = isSVGShadowRoot ? ancestor->svgShadowHost() : ancestor->shadowHost();
+#else
+ ancestor = ancestor->shadowHost();
+#endif
+ if (!shouldSkipNextAncestor)
+ target = ancestor;
+ } else
+ ancestor = ancestor->parentNodeGuaranteedHostFree();
+
+ if (!ancestor)
+ return;
+
+#if ENABLE(SVG)
+ // Skip SVGShadowTreeRootElement.
+ shouldSkipNextAncestor = ancestor->isSVGShadowRoot();
+ if (shouldSkipNextAncestor)
+ continue;
+#endif
+ // FIXME: Unroll the extra loop inside eventTargetRespectingSVGTargetRules into this loop.
+ m_ancestors.append(EventContext(ancestor, eventTargetRespectingSVGTargetRules(ancestor), target));
+ }
+}
+
+bool EventDispatcher::dispatchEvent(PassRefPtr<Event> event)
+{
+ event->setTarget(eventTargetRespectingSVGTargetRules(m_node.get()));
+
+ ASSERT(!eventDispatchForbidden());
+ ASSERT(event->target());
+ ASSERT(!event->type().isNull()); // JavaScript code can create an event with an empty name, but not null.
+
+ RefPtr<EventTarget> originalTarget = event->target();
+ ensureEventAncestors(event.get());
+
+ WindowEventContext windowContext(event.get(), m_node.get(), topEventContext());
+
+ InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchEvent(m_node->document(), *event, windowContext.window(), m_node.get(), m_ancestors);
+
+ // Give the target node a chance to do some work before DOM event handlers get a crack.
+ void* data = m_node->preDispatchEventHandler(event.get());
+ if (event->propagationStopped())
+ goto doneDispatching;
+
+ // Trigger capturing event handlers, starting at the top and working our way down.
+ event->setEventPhase(Event::CAPTURING_PHASE);
+
+ if (windowContext.handleLocalEvents(event.get()) && event->propagationStopped())
+ goto doneDispatching;
+
+ for (size_t i = m_ancestors.size(); i; --i) {
+ m_ancestors[i - 1].handleLocalEvents(event.get());
+ if (event->propagationStopped())
+ goto doneDispatching;
+ }
+
+ event->setEventPhase(Event::AT_TARGET);
+ event->setTarget(originalTarget.get());
+ event->setCurrentTarget(eventTargetRespectingSVGTargetRules(m_node.get()));
+ m_node->handleLocalEvents(event.get());
+ if (event->propagationStopped())
+ goto doneDispatching;
+
+ if (event->bubbles() && !event->cancelBubble()) {
+ // Trigger bubbling event handlers, starting at the bottom and working our way up.
+ event->setEventPhase(Event::BUBBLING_PHASE);
+
+ size_t size = m_ancestors.size();
+ for (size_t i = 0; i < size; ++i) {
+ m_ancestors[i].handleLocalEvents(event.get());
+ if (event->propagationStopped() || event->cancelBubble())
+ goto doneDispatching;
+ }
+ windowContext.handleLocalEvents(event.get());
+ }
+
+doneDispatching:
+ event->setTarget(originalTarget.get());
+ event->setCurrentTarget(0);
+ event->setEventPhase(0);
+
+ // Pass the data from the preDispatchEventHandler to the postDispatchEventHandler.
+ m_node->postDispatchEventHandler(event.get(), data);
+
+ // Call default event handlers. While the DOM does have a concept of preventing
+ // default handling, the detail of which handlers are called is an internal
+ // implementation detail and not part of the DOM.
+ if (!event->defaultPrevented() && !event->defaultHandled()) {
+ // Non-bubbling events call only one default event handler, the one for the target.
+ m_node->defaultEventHandler(event.get());
+ ASSERT(!event->defaultPrevented());
+ if (event->defaultHandled())
+ goto doneWithDefault;
+ // For bubbling events, call default event handlers on the same targets in the
+ // same order as the bubbling phase.
+ if (event->bubbles()) {
+ size_t size = m_ancestors.size();
+ for (size_t i = 0; i < size; ++i) {
+ m_ancestors[i].node()->defaultEventHandler(event.get());
+ ASSERT(!event->defaultPrevented());
+ if (event->defaultHandled())
+ goto doneWithDefault;
+ }
+ }
+ }
+
+doneWithDefault:
+
+ // Ensure that after event dispatch, the event's target object is the
+ // outermost shadow DOM boundary.
+ event->setTarget(windowContext.target());
+ event->setCurrentTarget(0);
+ InspectorInstrumentation::didDispatchEvent(cookie);
+
+ return !event->defaultPrevented();
+}
+
+const EventContext* EventDispatcher::topEventContext()
+{
+ return m_ancestors.isEmpty() ? 0 : &m_ancestors.last();
+}
+
+EventDispatchBehavior EventDispatcher::determineDispatchBehavior(Event* event)
+{
+ // Per XBL 2.0 spec, mutation events should never cross shadow DOM boundary:
+ // http://dev.w3.org/2006/xbl2/#event-flow-and-targeting-across-shadow-s
+ if (event->isMutationEvent())
+ return StayInsideShadowDOM;
+
+ // WebKit never allowed selectstart event to cross the the shadow DOM boundary.
+ // Changing this breaks existing sites.
+ // See https://bugs.webkit.org/show_bug.cgi?id=52195 for details.
+ if (event->type() == eventNames().selectstartEvent)
+ return StayInsideShadowDOM;
+
+ return RetargetEvent;
+}
+
+}
+
diff --git a/Source/WebCore/dom/EventDispatcher.h b/Source/WebCore/dom/EventDispatcher.h
new file mode 100644
index 0000000..88e9756
--- /dev/null
+++ b/Source/WebCore/dom/EventDispatcher.h
@@ -0,0 +1,82 @@
+/*
+ * 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, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+ * Copyright (C) 2011 Google 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 EventDispatcher_h
+#define EventDispatcher_h
+
+#include <wtf/Forward.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class Event;
+class EventContext;
+class EventDispatchMediator;
+class EventTarget;
+class FrameView;
+class Node;
+class PlatformKeyboardEvent;
+class PlatformMouseEvent;
+class PlatformWheelEvent;
+
+enum EventDispatchBehavior {
+ RetargetEvent,
+ StayInsideShadowDOM
+};
+
+class EventDispatcher {
+public:
+ static bool dispatchEvent(Node*, const EventDispatchMediator&);
+ static void dispatchScopedEvent(Node*, PassRefPtr<Event>);
+
+ static void dispatchSimulatedClick(Node*, PassRefPtr<Event> underlyingEvent, bool sendMouseEvents, bool showPressedLook);
+
+ bool dispatchEvent(PassRefPtr<Event>);
+ PassRefPtr<EventTarget> adjustRelatedTarget(Event*, PassRefPtr<EventTarget>);
+ Node* node() const;
+
+private:
+ EventDispatcher(Node*);
+
+ PassRefPtr<EventTarget> adjustToShadowBoundaries(PassRefPtr<Node> relatedTarget, const Vector<Node*> relatedTargetAncestors);
+ EventDispatchBehavior determineDispatchBehavior(Event*);
+ void ensureEventAncestors(Event*);
+ const EventContext* topEventContext();
+
+ Vector<EventContext> m_ancestors;
+ RefPtr<Node> m_node;
+ RefPtr<EventTarget> m_originalTarget;
+ RefPtr<FrameView> m_view;
+ bool m_ancestorsInitialized;
+};
+
+inline Node* EventDispatcher::node() const
+{
+ return m_node.get();
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/dom/EventNames.h b/Source/WebCore/dom/EventNames.h
index 12afbc4..c445a7d 100644
--- a/Source/WebCore/dom/EventNames.h
+++ b/Source/WebCore/dom/EventNames.h
@@ -67,8 +67,6 @@ namespace WebCore {
macro(focus) \
macro(focusin) \
macro(focusout) \
- macro(formchange) \
- macro(forminput) \
macro(hashchange) \
macro(input) \
macro(invalid) \
diff --git a/Source/WebCore/dom/EventQueue.cpp b/Source/WebCore/dom/EventQueue.cpp
index 8e544c1..90f3e5d 100644
--- a/Source/WebCore/dom/EventQueue.cpp
+++ b/Source/WebCore/dom/EventQueue.cpp
@@ -28,12 +28,20 @@
#include "EventQueue.h"
#include "DOMWindow.h"
+#include "Document.h"
#include "Event.h"
#include "EventNames.h"
+#include "RuntimeApplicationChecks.h"
#include "ScriptExecutionContext.h"
#include "SuspendableTimer.h"
namespace WebCore {
+
+static inline bool shouldDispatchScrollEventSynchronously(Document* document)
+{
+ ASSERT_ARG(document, document);
+ return applicationIsSafari() && (document->url().protocolIs("feed") || document->url().protocolIs("feeds"));
+}
class EventQueueTimer : public SuspendableTimer {
WTF_MAKE_NONCOPYABLE(EventQueueTimer);
@@ -71,14 +79,20 @@ void EventQueue::enqueueEvent(PassRefPtr<Event> event)
m_pendingEventTimer->startOneShot(0);
}
-void EventQueue::enqueueScrollEvent(PassRefPtr<Node> target, ScrollEventTargetType targetType)
+void EventQueue::enqueueOrDispatchScrollEvent(PassRefPtr<Node> target, ScrollEventTargetType targetType)
{
- if (!m_nodesWithQueuedScrollEvents.add(target.get()).second)
- return;
-
// Per the W3C CSSOM View Module, scroll events fired at the document should bubble, others should not.
bool canBubble = targetType == ScrollEventDocumentTarget;
RefPtr<Event> scrollEvent = Event::create(eventNames().scrollEvent, canBubble, false /* non cancelleable */);
+
+ if (shouldDispatchScrollEventSynchronously(target->document())) {
+ target->dispatchEvent(scrollEvent.release());
+ return;
+ }
+
+ if (!m_nodesWithQueuedScrollEvents.add(target.get()).second)
+ return;
+
scrollEvent->setTarget(target);
enqueueEvent(scrollEvent.release());
}
@@ -92,6 +106,12 @@ bool EventQueue::cancelEvent(Event* event)
return found;
}
+void EventQueue::cancelQueuedEvents()
+{
+ m_pendingEventTimer->stop();
+ m_queuedEvents.clear();
+}
+
void EventQueue::pendingEventTimerFired()
{
ASSERT(!m_pendingEventTimer->isActive());
diff --git a/Source/WebCore/dom/EventQueue.h b/Source/WebCore/dom/EventQueue.h
index 94b6eaf..2cb38f4 100644
--- a/Source/WebCore/dom/EventQueue.h
+++ b/Source/WebCore/dom/EventQueue.h
@@ -51,8 +51,9 @@ public:
~EventQueue();
void enqueueEvent(PassRefPtr<Event>);
- void enqueueScrollEvent(PassRefPtr<Node>, ScrollEventTargetType);
+ void enqueueOrDispatchScrollEvent(PassRefPtr<Node>, ScrollEventTargetType);
bool cancelEvent(Event*);
+ void cancelQueuedEvents();
private:
explicit EventQueue(ScriptExecutionContext*);
diff --git a/Source/WebCore/dom/EventTarget.cpp b/Source/WebCore/dom/EventTarget.cpp
index 7bd5cd6..d84d66b 100644
--- a/Source/WebCore/dom/EventTarget.cpp
+++ b/Source/WebCore/dom/EventTarget.cpp
@@ -119,6 +119,11 @@ SVGElementInstance* EventTarget::toSVGElementInstance()
#endif
#if ENABLE(WEB_AUDIO)
+AudioContext* EventTarget::toAudioContext()
+{
+ return 0;
+}
+
JavaScriptAudioNode* EventTarget::toJavaScriptAudioNode()
{
return 0;
diff --git a/Source/WebCore/dom/EventTarget.h b/Source/WebCore/dom/EventTarget.h
index 31644b7..3544ce6 100644
--- a/Source/WebCore/dom/EventTarget.h
+++ b/Source/WebCore/dom/EventTarget.h
@@ -40,6 +40,7 @@
namespace WebCore {
+ class AudioContext;
class AbstractWorker;
class DedicatedWorkerContext;
class DOMApplicationCache;
@@ -122,6 +123,7 @@ namespace WebCore {
#endif
#if ENABLE(WEB_AUDIO)
+ virtual AudioContext* toAudioContext();
virtual JavaScriptAudioNode* toJavaScriptAudioNode();
#endif
diff --git a/Source/WebCore/dom/ExceptionCode.h b/Source/WebCore/dom/ExceptionCode.h
index dd976c7..881c3a3 100644
--- a/Source/WebCore/dom/ExceptionCode.h
+++ b/Source/WebCore/dom/ExceptionCode.h
@@ -57,13 +57,13 @@ namespace WebCore {
NETWORK_ERR = 19,
ABORT_ERR = 20,
URL_MISMATCH_ERR = 21,
- QUOTA_EXCEEDED_ERR = 22,
+ QUOTA_EXCEEDED_ERR = 22
// Introduced in File API:
// http://www.w3.org/TR/file-upload/#dfn-fileerror
#if ENABLE(BLOB) || ENABLE(FILE_SYSTEM)
- NOT_READABLE_ERR = 24,
- ENCODING_ERR = 26,
+ , NOT_READABLE_ERR = 24
+ , ENCODING_ERR = 26
#endif
};
diff --git a/Source/WebCore/dom/InputElement.cpp b/Source/WebCore/dom/InputElement.cpp
index b60fd44..bbdf2f4 100644
--- a/Source/WebCore/dom/InputElement.cpp
+++ b/Source/WebCore/dom/InputElement.cpp
@@ -38,22 +38,13 @@
#include "Event.h"
#include "EventNames.h"
#include "Frame.h"
-#include "HTMLInputElement.h"
-#include "HTMLNames.h"
#include "Page.h"
#include "RenderTextControlSingleLine.h"
#include "SelectionController.h"
#include "TextIterator.h"
-#if ENABLE(WML)
-#include "WMLInputElement.h"
-#include "WMLNames.h"
-#endif
-
namespace WebCore {
-using namespace HTMLNames;
-
// FIXME: According to HTML4, the length attribute's value can be arbitrarily
// large. However, due to https://bugs.webkit.org/show_bug.cgi?id=14536 things
// get rather sluggish when a text field has a larger number of characters than
@@ -140,7 +131,7 @@ void InputElement::setValueFromRenderer(InputElementData& data, InputElement* in
// Input event is fired by the Node::defaultEventHandler for editable controls.
if (!inputElement->isTextField())
- element->dispatchInputEvents();
+ element->dispatchInputEvent();
notifyFormStateChanged(element);
}
@@ -287,19 +278,6 @@ const AtomicString& InputElementData::name() const
return m_name.isNull() ? emptyAtom : m_name;
}
-InputElement* toInputElement(Element* element)
-{
- if (element->isHTMLElement() && (element->hasTagName(inputTag) || element->hasTagName(isindexTag)))
- return static_cast<HTMLInputElement*>(element);
-
-#if ENABLE(WML)
- if (element->isWMLElement() && element->hasTagName(WMLNames::inputTag))
- return static_cast<WMLInputElement*>(element);
-#endif
-
- return 0;
-}
-
#if ENABLE(WCSS)
static inline const AtomicString& formatCodes()
{
diff --git a/Source/WebCore/dom/InputElement.h b/Source/WebCore/dom/InputElement.h
index 838adf5..26bf58d 100644
--- a/Source/WebCore/dom/InputElement.h
+++ b/Source/WebCore/dom/InputElement.h
@@ -160,8 +160,6 @@ private:
#endif
};
-InputElement* toInputElement(Element*);
-
}
#endif
diff --git a/Source/WebCore/dom/KeyboardEvent.cpp b/Source/WebCore/dom/KeyboardEvent.cpp
index 7b0f3af..e244fd2 100644
--- a/Source/WebCore/dom/KeyboardEvent.cpp
+++ b/Source/WebCore/dom/KeyboardEvent.cpp
@@ -25,6 +25,7 @@
#include "Document.h"
#include "DOMWindow.h"
+#include "EventDispatcher.h"
#include "EventNames.h"
#include "EventHandler.h"
#include "Frame.h"
@@ -160,4 +161,15 @@ KeyboardEvent* findKeyboardEvent(Event* event)
return 0;
}
+KeyboardEventDispatchMediator::KeyboardEventDispatchMediator(PassRefPtr<KeyboardEvent> event)
+ : EventDispatchMediator(event)
+{
+}
+
+bool KeyboardEventDispatchMediator::dispatchEvent(EventDispatcher* dispatcher) const
+{
+ // Make sure not to return true if we already took default action while handling the event.
+ return EventDispatchMediator::dispatchEvent(dispatcher) && !event()->defaultHandled();
+}
+
} // namespace WebCore
diff --git a/Source/WebCore/dom/KeyboardEvent.h b/Source/WebCore/dom/KeyboardEvent.h
index eeaef80..68910b5 100644
--- a/Source/WebCore/dom/KeyboardEvent.h
+++ b/Source/WebCore/dom/KeyboardEvent.h
@@ -29,15 +29,17 @@
namespace WebCore {
+ class EventDispatcher;
+ class Node;
class PlatformKeyboardEvent;
#if PLATFORM(MAC)
struct KeypressCommand {
KeypressCommand() { }
- KeypressCommand(const String& commandName) : commandName(commandName) { }
- KeypressCommand(const String& commandName, const String& text) : commandName(commandName), text(text) { }
+ KeypressCommand(const String& commandName) : commandName(commandName) { ASSERT(isASCIILower(commandName[0U])); }
+ KeypressCommand(const String& commandName, const String& text) : commandName(commandName), text(text) { ASSERT(commandName == "insertText:"); }
- String commandName;
+ String commandName; // Actually, a selector name - it may have a trailing colon, and a name that can be different from an editor command name.
String text;
};
#endif
@@ -105,13 +107,22 @@ namespace WebCore {
unsigned m_keyLocation;
bool m_altGraphKey : 1;
-#if PLATFORM(MAC)
+#if PLATFORM(MAC)
+ // Commands that were sent by AppKit when interpreting the event. Doesn't include input method commands.
Vector<KeypressCommand> m_keypressCommands;
#endif
};
KeyboardEvent* findKeyboardEvent(Event*);
+class KeyboardEventDispatchMediator : public EventDispatchMediator {
+public:
+ explicit KeyboardEventDispatchMediator(PassRefPtr<KeyboardEvent>);
+
+private:
+ virtual bool dispatchEvent(EventDispatcher*) const;
+};
+
} // namespace WebCore
#endif // KeyboardEvent_h
diff --git a/Source/WebCore/dom/MessagePort.cpp b/Source/WebCore/dom/MessagePort.cpp
index 1b7aea7..5edc36c 100644
--- a/Source/WebCore/dom/MessagePort.cpp
+++ b/Source/WebCore/dom/MessagePort.cpp
@@ -34,6 +34,7 @@
#include "MessageEvent.h"
#include "SecurityOrigin.h"
#include "Timer.h"
+#include "WorkerContext.h"
#include <wtf/text/AtomicString.h>
namespace WebCore {
@@ -171,6 +172,13 @@ void MessagePort::dispatchMessages()
OwnPtr<MessagePortChannel::EventData> eventData;
while (m_entangledChannel && m_entangledChannel->tryGetMessageFromRemote(eventData)) {
+
+#if ENABLE(WORKERS)
+ // close() in Worker onmessage handler should prevent next message from dispatching.
+ if (m_scriptExecutionContext->isWorkerContext() && static_cast<WorkerContext*>(m_scriptExecutionContext)->isClosing())
+ return;
+#endif
+
OwnPtr<MessagePortArray> ports = MessagePort::entanglePorts(*m_scriptExecutionContext, eventData->channels());
RefPtr<Event> evt = MessageEvent::create(ports.release(), eventData->message());
diff --git a/Source/WebCore/dom/MouseEvent.cpp b/Source/WebCore/dom/MouseEvent.cpp
index bdd39d3..134e5f6 100644
--- a/Source/WebCore/dom/MouseEvent.cpp
+++ b/Source/WebCore/dom/MouseEvent.cpp
@@ -23,10 +23,26 @@
#include "config.h"
#include "MouseEvent.h"
+#include "EventDispatcher.h"
#include "EventNames.h"
+#include "Frame.h"
+#include "FrameView.h"
+#include "PlatformMouseEvent.h"
namespace WebCore {
+PassRefPtr<MouseEvent> MouseEvent::create(const AtomicString& eventType, PassRefPtr<AbstractView> view, const PlatformMouseEvent& event, int detail, PassRefPtr<Node> relatedTarget)
+{
+ ASSERT(event.eventType() == MouseEventMoved || event.button() != NoButton);
+
+ bool isCancelable = eventType != eventNames().mousemoveEvent;
+
+ return MouseEvent::create(eventType, true, isCancelable, view,
+ detail, event.globalX(), event.globalY(), event.x(), event.y(),
+ event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(), event.button(),
+ relatedTarget, 0, false);
+}
+
MouseEvent::MouseEvent()
: m_button(0)
, m_buttonDown(false)
@@ -115,4 +131,68 @@ Node* MouseEvent::fromElement() const
return target() ? target()->toNode() : 0;
}
+PassRefPtr<SimulatedMouseEvent> SimulatedMouseEvent::create(const AtomicString& eventType, PassRefPtr<AbstractView> view, PassRefPtr<Event> underlyingEvent)
+{
+ return adoptRef(new SimulatedMouseEvent(eventType, view, underlyingEvent));
+}
+
+SimulatedMouseEvent::~SimulatedMouseEvent()
+{
+}
+
+SimulatedMouseEvent::SimulatedMouseEvent(const AtomicString& eventType, PassRefPtr<AbstractView> view, PassRefPtr<Event> underlyingEvent)
+ : MouseEvent(eventType, true, true, view, 0, 0, 0, 0, 0, false, false, false, false, 0, 0, 0, true)
+{
+ if (UIEventWithKeyState* keyStateEvent = findEventWithKeyState(underlyingEvent.get())) {
+ m_ctrlKey = keyStateEvent->ctrlKey();
+ m_altKey = keyStateEvent->altKey();
+ m_shiftKey = keyStateEvent->shiftKey();
+ m_metaKey = keyStateEvent->metaKey();
+ }
+ setUnderlyingEvent(underlyingEvent);
+}
+
+MouseEventDispatchMediator::MouseEventDispatchMediator(PassRefPtr<MouseEvent> mouseEvent)
+ : EventDispatchMediator(mouseEvent)
+{
+}
+
+MouseEvent* MouseEventDispatchMediator::event() const
+{
+ return static_cast<MouseEvent*>(EventDispatchMediator::event());
+}
+
+bool MouseEventDispatchMediator::dispatchEvent(EventDispatcher* dispatcher) const
+{
+ if (dispatcher->node()->disabled()) // Don't even send DOM events for disabled controls..
+ return true;
+
+ if (event()->type().isEmpty())
+ return false; // Shouldn't happen.
+
+ RefPtr<EventTarget> relatedTarget = dispatcher->adjustRelatedTarget(event(), event()->relatedTarget());
+ event()->setRelatedTarget(relatedTarget);
+
+ dispatcher->dispatchEvent(event());
+ bool swallowEvent = event()->defaultHandled() || event()->defaultPrevented();
+
+ // 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 (event()->type() == eventNames().clickEvent && event()->detail() == 2) {
+ RefPtr<MouseEvent> doubleClickEvent = MouseEvent::create();
+ doubleClickEvent->initMouseEvent(eventNames().dblclickEvent, event()->bubbles(), event()->cancelable(), event()->view(),
+ event()->detail(), event()->screenX(), event()->screenY(), event()->clientX(), event()->clientY(),
+ event()->ctrlKey(), event()->altKey(), event()->shiftKey(), event()->metaKey(),
+ event()->button(), relatedTarget);
+ if (event()->defaultHandled())
+ doubleClickEvent->setDefaultHandled();
+ dispatcher->dispatchEvent(doubleClickEvent);
+ if (doubleClickEvent->defaultHandled() || doubleClickEvent->defaultPrevented())
+ swallowEvent = true;
+ }
+
+ return swallowEvent;
+}
+
} // namespace WebCore
diff --git a/Source/WebCore/dom/MouseEvent.h b/Source/WebCore/dom/MouseEvent.h
index 7454b04..bab2b42 100644
--- a/Source/WebCore/dom/MouseEvent.h
+++ b/Source/WebCore/dom/MouseEvent.h
@@ -29,6 +29,9 @@
namespace WebCore {
+class EventDispatcher;
+class PlatformMouseEvent;
+
// Introduced in DOM Level 2
class MouseEvent : public MouseRelatedEvent {
public:
@@ -44,6 +47,8 @@ namespace WebCore {
return adoptRef(new MouseEvent(type, canBubble, cancelable, view, detail, screenX, screenY, pageX, pageY,
ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget, clipboard, isSimulated));
}
+ static PassRefPtr<MouseEvent> create(const AtomicString& eventType, PassRefPtr<AbstractView>, const PlatformMouseEvent&, int detail, PassRefPtr<Node> relatedTarget);
+
virtual ~MouseEvent();
void initMouseEvent(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<AbstractView>,
@@ -56,6 +61,7 @@ namespace WebCore {
unsigned short button() const { return m_button; }
bool buttonDown() const { return m_buttonDown; }
EventTarget* relatedTarget() const { return m_relatedTarget.get(); }
+ void setRelatedTarget(PassRefPtr<EventTarget> relatedTarget) { m_relatedTarget = relatedTarget; }
Clipboard* clipboard() const { return m_clipboard.get(); }
@@ -68,19 +74,40 @@ namespace WebCore {
virtual bool isDragEvent() const;
virtual int which() const;
- private:
- MouseEvent();
+ protected:
MouseEvent(const AtomicString& type, bool canBubble, bool cancelable, PassRefPtr<AbstractView>,
int detail, int screenX, int screenY, int pageX, int pageY,
bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, unsigned short button,
PassRefPtr<EventTarget> relatedTarget, PassRefPtr<Clipboard> clipboard, bool isSimulated);
+ private:
+ MouseEvent();
+
unsigned short m_button;
bool m_buttonDown;
RefPtr<EventTarget> m_relatedTarget;
RefPtr<Clipboard> m_clipboard;
};
+class SimulatedMouseEvent : public MouseEvent {
+public:
+ static PassRefPtr<SimulatedMouseEvent> create(const AtomicString& eventType, PassRefPtr<AbstractView>, PassRefPtr<Event> underlyingEvent);
+ virtual ~SimulatedMouseEvent();
+
+private:
+ SimulatedMouseEvent(const AtomicString& eventType, PassRefPtr<AbstractView>, PassRefPtr<Event> underlyingEvent);
+};
+
+class MouseEventDispatchMediator : public EventDispatchMediator {
+public:
+ explicit MouseEventDispatchMediator(PassRefPtr<MouseEvent>);
+
+private:
+ MouseEvent* event() const;
+
+ virtual bool dispatchEvent(EventDispatcher*) const;
+};
+
} // namespace WebCore
#endif // MouseEvent_h
diff --git a/Source/WebCore/dom/MouseRelatedEvent.cpp b/Source/WebCore/dom/MouseRelatedEvent.cpp
index 072656e..01e2d19 100644
--- a/Source/WebCore/dom/MouseRelatedEvent.cpp
+++ b/Source/WebCore/dom/MouseRelatedEvent.cpp
@@ -44,6 +44,7 @@ MouseRelatedEvent::MouseRelatedEvent()
, m_offsetX(0)
, m_offsetY(0)
, m_isSimulated(false)
+ , m_hasCachedRelativePosition(false)
{
}
@@ -73,39 +74,63 @@ static int contentsY(AbstractView* abstractView)
return frameView->scrollY() / frame->pageZoomFactor();
}
-MouseRelatedEvent::MouseRelatedEvent(const AtomicString& eventType, bool canBubble, bool cancelable, PassRefPtr<AbstractView> viewArg,
- int detail, int screenX, int screenY, int pageX, int pageY,
+MouseRelatedEvent::MouseRelatedEvent(const AtomicString& eventType, bool canBubble, bool cancelable, PassRefPtr<AbstractView> abstractView,
+ int detail, int screenX, int screenY, int windowX, int windowY,
bool ctrlKey, bool altKey, bool shiftKey, bool metaKey, bool isSimulated)
- : UIEventWithKeyState(eventType, canBubble, cancelable, viewArg, detail, ctrlKey, altKey, shiftKey, metaKey)
+ : UIEventWithKeyState(eventType, canBubble, cancelable, abstractView, 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_clientX(0)
+ , m_clientY(0)
+ , m_pageX(0)
+ , m_pageY(0)
, m_isSimulated(isSimulated)
{
+ IntPoint adjustedPageLocation;
+ IntPoint scrollPosition;
+
+ Frame* frame = view() ? view()->frame() : 0;
+ if (frame && !isSimulated) {
+ if (FrameView* frameView = frame->view()) {
+ scrollPosition = frameView->scrollPosition();
+ adjustedPageLocation = frameView->windowToContents(IntPoint(windowX, windowY));
+ float pageZoom = frame->pageZoomFactor();
+ if (pageZoom != 1.0f) {
+ // Adjust our pageX and pageY to account for the page zoom.
+ adjustedPageLocation.setX(lroundf(adjustedPageLocation.x() / pageZoom));
+ adjustedPageLocation.setY(lroundf(adjustedPageLocation.y() / pageZoom));
+ scrollPosition.setX(scrollPosition.x() / pageZoom);
+ scrollPosition.setY(scrollPosition.y() / pageZoom);
+ }
+ }
+ }
+
+ IntPoint clientLocation(adjustedPageLocation - scrollPosition);
+ m_clientX = clientLocation.x();
+ m_clientY = clientLocation.y();
+ m_pageX = adjustedPageLocation.x();
+ m_pageY = adjustedPageLocation.y();
+
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.
+ // Correct values are computed lazily, see computeRelativePosition.
m_layerX = m_pageX;
m_layerY = m_pageY;
m_offsetX = m_pageX;
m_offsetY = m_pageY;
computePageLocation();
+ m_hasCachedRelativePosition = false;
}
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.
+ // Correct values are computed lazily, see computeRelativePosition.
m_clientX = clientX;
m_clientY = clientY;
m_pageX = clientX + contentsX(view());
@@ -116,9 +141,10 @@ void MouseRelatedEvent::initCoordinates(int clientX, int clientY)
m_offsetY = m_pageY;
computePageLocation();
+ m_hasCachedRelativePosition = false;
}
-static float pageZoomFactor(UIEvent* event)
+static float pageZoomFactor(const UIEvent* event)
{
DOMWindow* window = event->view();
if (!window)
@@ -137,9 +163,13 @@ void MouseRelatedEvent::computePageLocation()
void MouseRelatedEvent::receivedTarget()
{
- ASSERT(target());
- Node* targ = target()->toNode();
- if (!targ)
+ m_hasCachedRelativePosition = false;
+}
+
+void MouseRelatedEvent::computeRelativePosition()
+{
+ Node* targetNode = target() ? target()->toNode() : 0;
+ if (!targetNode)
return;
// Compute coordinates that are based on the target.
@@ -149,11 +179,11 @@ void MouseRelatedEvent::receivedTarget()
m_offsetY = m_pageY;
// Must have an updated render tree for this math to work correctly.
- targ->document()->updateStyleIfNeeded();
+ targetNode->document()->updateStyleIfNeeded();
// Adjust offsetX/Y to be relative to the target's position.
if (!isSimulated()) {
- if (RenderObject* r = targ->renderer()) {
+ if (RenderObject* r = targetNode->renderer()) {
FloatPoint localPos = r->absoluteToLocal(absoluteLocation(), false, true);
float zoomFactor = pageZoomFactor(this);
m_offsetX = lroundf(localPos.x() / zoomFactor);
@@ -166,17 +196,48 @@ void MouseRelatedEvent::receivedTarget()
// 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;
+ Node* n = targetNode;
while (n && !n->renderer())
n = n->parentNode();
- if (n) {
- RenderLayer* layer = n->renderer()->enclosingLayer();
+
+ RenderLayer* layer;
+ if (n && (layer = n->renderer()->enclosingLayer())) {
layer->updateLayerPosition();
for (; layer; layer = layer->parent()) {
m_layerX -= layer->x();
m_layerY -= layer->y();
}
}
+
+ m_hasCachedRelativePosition = true;
+}
+
+int MouseRelatedEvent::layerX()
+{
+ if (!m_hasCachedRelativePosition)
+ computeRelativePosition();
+ return m_layerX;
+}
+
+int MouseRelatedEvent::layerY()
+{
+ if (!m_hasCachedRelativePosition)
+ computeRelativePosition();
+ return m_layerY;
+}
+
+int MouseRelatedEvent::offsetX()
+{
+ if (!m_hasCachedRelativePosition)
+ computeRelativePosition();
+ return m_offsetX;
+}
+
+int MouseRelatedEvent::offsetY()
+{
+ if (!m_hasCachedRelativePosition)
+ computeRelativePosition();
+ return m_offsetY;
}
int MouseRelatedEvent::pageX() const
diff --git a/Source/WebCore/dom/MouseRelatedEvent.h b/Source/WebCore/dom/MouseRelatedEvent.h
index fc494d1..b03b28a 100644
--- a/Source/WebCore/dom/MouseRelatedEvent.h
+++ b/Source/WebCore/dom/MouseRelatedEvent.h
@@ -38,10 +38,10 @@ namespace WebCore {
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; }
+ int layerX();
+ int layerY();
+ int offsetX();
+ int offsetY();
bool isSimulated() const { return m_isSimulated; }
virtual int pageX() const;
virtual int pageY() const;
@@ -64,6 +64,7 @@ namespace WebCore {
virtual void receivedTarget();
void computePageLocation();
+ void computeRelativePosition();
// Expose these so MouseEvent::initMouseEvent can set them.
int m_screenX;
@@ -80,6 +81,7 @@ namespace WebCore {
int m_offsetY;
IntPoint m_absoluteLocation;
bool m_isSimulated;
+ bool m_hasCachedRelativePosition;
};
} // namespace WebCore
diff --git a/Source/WebCore/dom/NamedNodeMap.cpp b/Source/WebCore/dom/NamedNodeMap.cpp
index 2861226..6fa30bf 100644
--- a/Source/WebCore/dom/NamedNodeMap.cpp
+++ b/Source/WebCore/dom/NamedNodeMap.cpp
@@ -100,12 +100,6 @@ PassRefPtr<Node> NamedNodeMap::setNamedItem(Node* arg, ExceptionCode& ec)
return 0;
}
- // WRONG_DOCUMENT_ERR: Raised if arg was created from a different document than the one that created this map.
- if (arg->document() != m_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;
diff --git a/Source/WebCore/dom/NamedNodeMap.idl b/Source/WebCore/dom/NamedNodeMap.idl
index 4d36577..3350d2f 100644
--- a/Source/WebCore/dom/NamedNodeMap.idl
+++ b/Source/WebCore/dom/NamedNodeMap.idl
@@ -21,6 +21,7 @@
module core {
interface [
+ CustomToJS,
CustomMarkFunction,
HasIndexGetter,
HasNameGetter
diff --git a/Source/WebCore/dom/Node.cpp b/Source/WebCore/dom/Node.cpp
index c125d16..1fd4b92 100644
--- a/Source/WebCore/dom/Node.cpp
+++ b/Source/WebCore/dom/Node.cpp
@@ -51,6 +51,7 @@
#include "Element.h"
#include "Event.h"
#include "EventContext.h"
+#include "EventDispatcher.h"
#include "EventException.h"
#include "EventHandler.h"
#include "EventListener.h"
@@ -106,10 +107,13 @@
#if ENABLE(SVG)
#include "SVGElementInstance.h"
-#include "SVGNames.h"
#include "SVGUseElement.h"
#endif
+#if ENABLE(WML)
+#include "WMLNames.h"
+#endif
+
#if ENABLE(XHTMLMP)
#include "HTMLNoScriptElement.h"
#endif
@@ -126,8 +130,6 @@ namespace WebCore {
using namespace HTMLNames;
-static HashSet<Node*>* gNodesDispatchingSimulatedClicks = 0;
-
bool Node::isSupported(const String& feature, const String& version)
{
return DOMImplementation::hasFeature(feature, version);
@@ -347,6 +349,12 @@ Node::StyleChange Node::diff(const RenderStyle* s1, const RenderStyle* s2)
}
}
+ // When text-combine property has been changed, we need to prepare a separate renderer object.
+ // When text-combine is on, we use RenderCombineText, otherwise RenderText.
+ // https://bugs.webkit.org/show_bug.cgi?id=55069
+ if ((s1 && s2) && (s1->hasTextCombine() != s2->hasTextCombine()))
+ ch = Detach;
+
return ch;
}
@@ -403,7 +411,7 @@ Node::~Node()
m_next->setPreviousSibling(0);
if (m_document)
- m_document->selfOnlyDeref();
+ m_document->guardDeref();
}
#ifdef NDEBUG
@@ -439,16 +447,12 @@ void Node::setDocument(Document* document)
if (inDocument() || m_document == document)
return;
- document->selfOnlyRef();
+ document->guardRef();
setWillMoveToNewOwnerDocumentWasCalled(false);
willMoveToNewOwnerDocument();
ASSERT(willMoveToNewOwnerDocumentWasCalled);
-#if USE(JSC)
- updateDOMNodeDocument(this, m_document, document);
-#endif
-
if (hasRareData() && rareData()->nodeLists()) {
if (m_document)
m_document->removeNodeListCache();
@@ -457,7 +461,7 @@ void Node::setDocument(Document* document)
if (m_document) {
m_document->moveNodeIteratorsToNewDocument(this, document);
- m_document->selfOnlyDeref();
+ m_document->guardDeref();
}
m_document = document;
@@ -467,6 +471,58 @@ void Node::setDocument(Document* document)
ASSERT(didMoveToNewOwnerDocumentWasCalled);
}
+TreeScope* Node::treeScope() const
+{
+ if (!hasRareData())
+ return document();
+ TreeScope* scope = rareData()->treeScope();
+ // FIXME: Until we land shadow scopes, there should be no non-document scopes.
+ ASSERT(!scope);
+ return scope ? scope : document();
+}
+
+void Node::setTreeScope(TreeScope* newTreeScope)
+{
+ ASSERT(!isDocumentNode());
+ ASSERT(newTreeScope);
+ ASSERT(!inDocument() || treeScope() == newTreeScope);
+
+ if (newTreeScope->isDocumentNode()) {
+ if (hasRareData())
+ rareData()->setTreeScope(0);
+ // Setting the new document scope will be handled implicitly
+ // by setDocument() below.
+ } else {
+ // FIXME: Until we land shadow scopes, this branch should be inert.
+ ASSERT_NOT_REACHED();
+ ensureRareData()->setTreeScope(newTreeScope);
+ }
+
+ setDocument(newTreeScope->document());
+}
+
+void Node::setTreeScopeRecursively(TreeScope* newTreeScope)
+{
+ ASSERT(!isDocumentNode());
+ ASSERT(newTreeScope);
+ if (treeScope() == newTreeScope)
+ return;
+
+ Document* currentDocument = document();
+ Document* newDocument = newTreeScope->document();
+ // If an element is moved from a document and then eventually back again the collection cache for
+ // that element may contain stale data as changes made to it will have updated the DOMTreeVersion
+ // of the document it was moved to. By increasing the DOMTreeVersion of the donating document here
+ // we ensure that the collection cache will be invalidated as needed when the element is moved back.
+ if (currentDocument && currentDocument != newDocument)
+ currentDocument->incDOMTreeVersion();
+
+ for (Node* node = this; node; node = node->traverseNextNode(this)) {
+ node->setTreeScope(newTreeScope);
+ // FIXME: Once shadow scopes are landed, update parent scope, etc.
+ }
+}
+
NodeRareData* Node::rareData() const
{
ASSERT(hasRareData());
@@ -497,7 +553,7 @@ Element* Node::shadowHost() const
void Node::setShadowHost(Element* host)
{
- ASSERT(!parentNode());
+ ASSERT(!parentNode() && !isSVGShadowRoot());
if (host)
setFlag(IsShadowRootFlag);
else
@@ -506,6 +562,18 @@ void Node::setShadowHost(Element* host)
setParent(host);
}
+InputElement* Node::toInputElement()
+{
+ // If one of the below ASSERTs trigger, you are calling this function
+ // directly or indirectly from a constructor or destructor of this object.
+ // Don't do this!
+ ASSERT(!(isHTMLElement() && hasTagName(inputTag)));
+#if ENABLE(WML)
+ ASSERT(!(isWMLElement() && hasTagName(WMLNames::inputTag)));
+#endif
+ return 0;
+}
+
short Node::tabIndex() const
{
return hasRareData() ? rareData()->tabIndex() : 0;
@@ -696,12 +764,35 @@ void Node::deprecatedParserAddChild(PassRefPtr<Node>)
bool Node::isContentEditable() const
{
- return parentOrHostNode() && parentOrHostNode()->isContentEditable();
+ document()->updateLayoutIgnorePendingStylesheets();
+ return rendererIsEditable(Editable);
}
-bool Node::isContentRichlyEditable() const
+bool Node::rendererIsEditable(EditableLevel editableLevel) const
{
- return parentOrHostNode() && parentOrHostNode()->isContentRichlyEditable();
+ if (document()->inDesignMode() || (document()->frame() && document()->frame()->page() && document()->frame()->page()->isEditable()))
+ return true;
+
+ // Ideally we'd call ASSERT(!needsStyleRecalc()) here, but
+ // ContainerNode::setFocus() calls setNeedsStyleRecalc(), so the assertion
+ // would fire in the middle of Document::setFocusedNode().
+
+ for (const Node* node = this; node; node = node->parentNode()) {
+ if ((node->isHTMLElement() || node->isDocumentNode()) && node->renderer()) {
+ switch (node->renderer()->style()->userModify()) {
+ case READ_ONLY:
+ return false;
+ case READ_WRITE:
+ return true;
+ case READ_WRITE_PLAINTEXT_ONLY:
+ return editableLevel != RichlyEditable;
+ }
+ ASSERT_NOT_REACHED();
+ return false;
+ }
+ }
+
+ return false;
}
bool Node::shouldUseInputMethod() const
@@ -762,18 +853,21 @@ bool Node::hasNonEmptyBoundingBox() const
return false;
}
-void Node::setDocumentRecursively(Document* document)
+inline static ContainerNode* shadowRoot(Node* node)
{
- // FIXME: To match Gecko, we should do this for nodes that are already in the document as well.
- if (this->document() == document || this->inDocument())
- return;
+ return node->isElementNode() ? toElement(node)->shadowRoot() : 0;
+}
+
+void Node::setDocumentRecursively(Document* newDocument)
+{
+ ASSERT(document() != newDocument);
for (Node* node = this; node; node = node->traverseNextNode(this)) {
- node->setDocument(document);
+ node->setDocument(newDocument);
if (!node->isElementNode())
continue;
- if (Node* shadow = toElement(node)->shadowRoot())
- shadow->setDocumentRecursively(document);
+ if (Node* shadow = shadowRoot(node))
+ shadow->setDocumentRecursively(newDocument);
}
}
@@ -1147,37 +1241,25 @@ bool Node::canReplaceChild(Node* newChild, Node*)
static void checkAcceptChild(Node* newParent, Node* newChild, ExceptionCode& ec)
{
- // Perform error checking as required by spec for adding a new child. Used by replaceChild().
-
// 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 (newParent->isReadOnlyNode()) {
ec = NO_MODIFICATION_ALLOWED_ERR;
return;
}
-
- // 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() != newParent->document() && newChild->inDocument()) {
- // 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.
- ec = WRONG_DOCUMENT_ERR;
+
+ if (newChild->inDocument() && newChild->nodeType() == Node::DOCUMENT_TYPE_NODE) {
+ ec = HIERARCHY_REQUEST_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 == newParent || newParent->isDescendantOf(newChild)) {
ec = HIERARCHY_REQUEST_ERR;
return;
@@ -1186,6 +1268,11 @@ static void checkAcceptChild(Node* newParent, Node* newChild, ExceptionCode& ec)
void Node::checkReplaceChild(Node* newChild, Node* oldChild, ExceptionCode& ec)
{
+ if (!oldChild) {
+ ec = NOT_FOUND_ERR;
+ return;
+ }
+
checkAcceptChild(this, newChild, ec);
if (ec)
return;
@@ -1365,18 +1452,44 @@ Node *Node::nextLeafNode() const
return 0;
}
+ContainerNode* Node::parentNodeForRenderingAndStyle() const
+{
+ ContainerNode* parent = parentOrHostNode();
+ return parent && parent->isShadowBoundary() ? parent->shadowHost() : parent;
+}
+
+static bool shouldCreateRendererFor(Node* node, ContainerNode* parentForRenderingAndStyle)
+{
+ RenderObject* parentRenderer = parentForRenderingAndStyle->renderer();
+ if (!parentRenderer)
+ return false;
+
+ bool atShadowBoundary = node->parentOrHostNode()->isShadowBoundary();
+
+ // FIXME: Ignoring canHaveChildren() in a case of isShadowRoot() might be wrong.
+ // See https://bugs.webkit.org/show_bug.cgi?id=52423
+ if (!parentRenderer->canHaveChildren() && !(node->isShadowRoot() || atShadowBoundary))
+ return false;
+
+ if (shadowRoot(parentForRenderingAndStyle) && !atShadowBoundary
+ && !parentForRenderingAndStyle->canHaveLightChildRendererWithShadow())
+ return false;
+
+ if (!parentForRenderingAndStyle->childShouldCreateRenderer(node))
+ return false;
+
+ return true;
+}
+
RenderObject* Node::createRendererAndStyle()
{
ASSERT(!renderer());
ASSERT(document()->shouldCreateRenderers());
- ContainerNode* parent = parentOrHostNode();
+ ContainerNode* parent = parentNodeForRenderingAndStyle();
ASSERT(parent);
- RenderObject* parentRenderer = parent->renderer();
- // FIXME: Ignoring canHaveChildren() in a case of isShadowRoot() might be wrong.
- // See https://bugs.webkit.org/show_bug.cgi?id=52423
- if (!parentRenderer || (!parentRenderer->canHaveChildren() && !isShadowRoot()) || !parent->childShouldCreateRenderer(this))
+ if (!shouldCreateRendererFor(this, parent))
return 0;
RefPtr<RenderStyle> style = styleForRenderer();
@@ -1387,7 +1500,7 @@ RenderObject* Node::createRendererAndStyle()
if (!newRenderer)
return 0;
- if (!parentRenderer->isChildAllowed(newRenderer, style.get())) {
+ if (!parent->renderer()->isChildAllowed(newRenderer, style.get())) {
newRenderer->destroy();
return 0;
}
@@ -1428,7 +1541,7 @@ void Node::createRendererIfNeeded()
return;
// Note: Adding newRenderer instead of renderer(). renderer() may be a child of newRenderer.
- parentOrHostNode()->renderer()->addChild(newRenderer, nextRenderer());
+ parentNodeForRenderingAndStyle()->renderer()->addChild(newRenderer, nextRenderer());
}
PassRefPtr<RenderStyle> Node::styleForRenderer()
@@ -1481,7 +1594,7 @@ int Node::maxCharacterOffset() const
// is obviously misplaced.
bool Node::canStartSelection() const
{
- if (isContentEditable())
+ if (rendererIsEditable())
return true;
if (renderer()) {
@@ -1494,6 +1607,13 @@ bool Node::canStartSelection() const
return parentOrHostNode() ? parentOrHostNode()->canStartSelection() : true;
}
+#if ENABLE(SVG)
+SVGUseElement* Node::svgShadowHost() const
+{
+ return isSVGShadowRoot() ? static_cast<SVGUseElement*>(parent()) : 0;
+}
+#endif
+
Node* Node::shadowAncestorNode()
{
#if ENABLE(SVG)
@@ -1515,7 +1635,7 @@ Node* Node::shadowTreeRootNode()
{
Node* root = this;
while (root) {
- if (root->isShadowRoot())
+ if (root->isShadowRoot() || root->isSVGShadowRoot())
return root;
root = root->parentNodeGuaranteedHostFree();
}
@@ -1559,7 +1679,7 @@ Element *Node::enclosingBlockFlowElement() const
Element* Node::rootEditableElement() const
{
Element* result = 0;
- for (Node* n = const_cast<Node*>(this); n && n->isContentEditable(); n = n->parentNode()) {
+ for (Node* n = const_cast<Node*>(this); n && n->rendererIsEditable(); n = n->parentNode()) {
if (n->isElementNode())
result = static_cast<Element*>(n);
if (n->hasTagName(bodyTag))
@@ -2605,28 +2725,6 @@ EventTargetData* Node::ensureEventTargetData()
return ensureRareData()->ensureEventTargetData();
}
-#if USE(JSC)
-
-template <class NodeListMap>
-void markNodeLists(const NodeListMap& map, JSC::MarkStack& markStack, JSC::JSGlobalData& globalData)
-{
- for (typename NodeListMap::const_iterator it = map.begin(); it != map.end(); ++it)
- markDOMObjectWrapper(markStack, globalData, it->second);
-}
-
-void Node::markCachedNodeListsSlow(JSC::MarkStack& markStack, JSC::JSGlobalData& globalData)
-{
- NodeListsNodeData* nodeLists = rareData()->nodeLists();
- if (!nodeLists)
- return;
-
- markNodeLists(nodeLists->m_classNodeListCache, markStack, globalData);
- markNodeLists(nodeLists->m_nameNodeListCache, markStack, globalData);
- markNodeLists(nodeLists->m_tagNodeListCache, markStack, globalData);
-}
-
-#endif
-
void Node::handleLocalEvents(Event* event)
{
if (!hasRareData() || !rareData()->eventTargetData())
@@ -2638,200 +2736,14 @@ void Node::handleLocalEvents(Event* event)
fireEventListeners(event);
}
-static inline EventTarget* eventTargetRespectingSVGTargetRules(Node* referenceNode)
-{
- ASSERT(referenceNode);
-
-#if ENABLE(SVG)
- if (!referenceNode->isSVGElement())
- return referenceNode;
-
- // Spec: The event handling for the non-exposed tree works as if the referenced element had been textually included
- // as a deeply cloned child of the 'use' element, except that events are dispatched to the SVGElementInstance objects
- for (Node* n = referenceNode; n; n = n->parentNode()) {
- if (!n->isShadowRoot() || !n->isSVGElement())
- continue;
-
- Element* shadowTreeParentElement = n->shadowHost();
- ASSERT(shadowTreeParentElement->hasTagName(SVGNames::useTag));
-
- if (SVGElementInstance* instance = static_cast<SVGUseElement*>(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode))
- return instance;
- }
-#endif
-
- return referenceNode;
-}
-
-void Node::getEventAncestors(Vector<EventContext>& ancestors, EventTarget* originalTarget, EventDispatchBehavior behavior)
-{
- if (!inDocument())
- return;
-
- EventTarget* target = originalTarget;
- Node* ancestor = this;
- bool shouldSkipNextAncestor = false;
- while (true) {
- if (ancestor->isShadowRoot()) {
- if (behavior == StayInsideShadowDOM)
- return;
- ancestor = ancestor->shadowHost();
- if (!shouldSkipNextAncestor)
- target = ancestor;
- } else
- ancestor = ancestor->parentNodeGuaranteedHostFree();
-
- if (!ancestor)
- return;
-
-#if ENABLE(SVG)
- // Skip SVGShadowTreeRootElement.
- shouldSkipNextAncestor = ancestor->isSVGElement() && ancestor->isShadowRoot();
- if (shouldSkipNextAncestor)
- continue;
-#endif
- // FIXME: Unroll the extra loop inside eventTargetRespectingSVGTargetRules into this loop.
- ancestors.append(EventContext(ancestor, eventTargetRespectingSVGTargetRules(ancestor), target));
-
- }
-}
-
-bool Node::dispatchEvent(PassRefPtr<Event> prpEvent)
-{
- RefPtr<EventTarget> protect = this;
- RefPtr<Event> event = prpEvent;
-
- event->setTarget(eventTargetRespectingSVGTargetRules(this));
-
- RefPtr<FrameView> view = document()->view();
- return dispatchGenericEvent(event.release());
-}
-
void Node::dispatchScopedEvent(PassRefPtr<Event> event)
{
- // We need to set the target here because it can go away by the time we actually fire the event.
- event->setTarget(eventTargetRespectingSVGTargetRules(this));
-
- ScopedEventQueue::instance()->enqueueEvent(event);
+ EventDispatcher::dispatchScopedEvent(this, event);
}
-static const EventContext* topEventContext(const Vector<EventContext>& ancestors)
+bool Node::dispatchEvent(PassRefPtr<Event> event)
{
- return ancestors.isEmpty() ? 0 : &ancestors.last();
-}
-
-static EventDispatchBehavior determineDispatchBehavior(Event* event)
-{
- // Per XBL 2.0 spec, mutation events should never cross shadow DOM boundary:
- // http://dev.w3.org/2006/xbl2/#event-flow-and-targeting-across-shadow-s
- if (event->isMutationEvent())
- return StayInsideShadowDOM;
-
- // WebKit never allowed selectstart event to cross the the shadow DOM boundary.
- // Changing this breaks existing sites.
- // See https://bugs.webkit.org/show_bug.cgi?id=52195 for details.
- if (event->type() == eventNames().selectstartEvent)
- return StayInsideShadowDOM;
-
- return RetargetEvent;
-}
-
-bool Node::dispatchGenericEvent(PassRefPtr<Event> prpEvent)
-{
- RefPtr<Event> event(prpEvent);
-
- ASSERT(!eventDispatchForbidden());
- ASSERT(event->target());
- ASSERT(!event->type().isNull()); // JavaScript code can create an event with an empty name, but not null.
-
- // Make a vector of ancestors to send the event to.
- // If the node is not in a document just send the event to it.
- // Be sure to ref all of nodes since event handlers could result in the last reference going away.
- RefPtr<Node> thisNode(this);
- RefPtr<EventTarget> originalTarget = event->target();
- Vector<EventContext> ancestors;
- getEventAncestors(ancestors, originalTarget.get(), determineDispatchBehavior(event.get()));
-
- WindowEventContext windowContext(event.get(), this, topEventContext(ancestors));
-
- InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchEvent(document(), *event, windowContext.window(), this, ancestors);
-
- // Give the target node a chance to do some work before DOM event handlers get a crack.
- void* data = preDispatchEventHandler(event.get());
- if (event->propagationStopped())
- goto doneDispatching;
-
- // Trigger capturing event handlers, starting at the top and working our way down.
- event->setEventPhase(Event::CAPTURING_PHASE);
-
- if (windowContext.handleLocalEvents(event.get()) && event->propagationStopped())
- goto doneDispatching;
-
- for (size_t i = ancestors.size(); i; --i) {
- ancestors[i - 1].handleLocalEvents(event.get());
- if (event->propagationStopped())
- goto doneDispatching;
- }
-
- event->setEventPhase(Event::AT_TARGET);
- event->setTarget(originalTarget.get());
- event->setCurrentTarget(eventTargetRespectingSVGTargetRules(this));
- handleLocalEvents(event.get());
- if (event->propagationStopped())
- goto doneDispatching;
-
- if (event->bubbles() && !event->cancelBubble()) {
- // Trigger bubbling event handlers, starting at the bottom and working our way up.
- event->setEventPhase(Event::BUBBLING_PHASE);
-
- size_t size = ancestors.size();
- for (size_t i = 0; i < size; ++i) {
- ancestors[i].handleLocalEvents(event.get());
- if (event->propagationStopped() || event->cancelBubble())
- goto doneDispatching;
- }
- windowContext.handleLocalEvents(event.get());
- }
-
-doneDispatching:
- event->setTarget(originalTarget.get());
- event->setCurrentTarget(0);
- event->setEventPhase(0);
-
- // Pass the data from the preDispatchEventHandler to the postDispatchEventHandler.
- postDispatchEventHandler(event.get(), data);
-
- // Call default event handlers. While the DOM does have a concept of preventing
- // default handling, the detail of which handlers are called is an internal
- // implementation detail and not part of the DOM.
- if (!event->defaultPrevented() && !event->defaultHandled()) {
- // Non-bubbling events call only one default event handler, the one for the target.
- defaultEventHandler(event.get());
- ASSERT(!event->defaultPrevented());
- if (event->defaultHandled())
- goto doneWithDefault;
- // For bubbling events, call default event handlers on the same targets in the
- // same order as the bubbling phase.
- if (event->bubbles()) {
- size_t size = ancestors.size();
- for (size_t i = 0; i < size; ++i) {
- ancestors[i].node()->defaultEventHandler(event.get());
- ASSERT(!event->defaultPrevented());
- if (event->defaultHandled())
- goto doneWithDefault;
- }
- }
- }
-
-doneWithDefault:
-
- // Ensure that after event dispatch, the event's target object is the
- // outermost shadow DOM boundary.
- event->setTarget(windowContext.target());
- event->setCurrentTarget(0);
- InspectorInstrumentation::didDispatchEvent(cookie);
-
- return !event->defaultPrevented();
+ return EventDispatcher::dispatchEvent(this, EventDispatchMediator(event));
}
void Node::dispatchSubtreeModifiedEvent()
@@ -2861,209 +2773,25 @@ void Node::dispatchUIEvent(const AtomicString& eventType, int detail, PassRefPtr
dispatchScopedEvent(event.release());
}
-bool Node::dispatchKeyEvent(const PlatformKeyboardEvent& key)
+bool Node::dispatchKeyEvent(const PlatformKeyboardEvent& event)
{
- RefPtr<KeyboardEvent> keyboardEvent = KeyboardEvent::create(key, document()->defaultView());
- bool r = dispatchEvent(keyboardEvent);
-
- // 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;
+ return EventDispatcher::dispatchEvent(this, KeyboardEventDispatchMediator(KeyboardEvent::create(event, document()->defaultView())));
}
bool Node::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, 0);
-}
-
-void Node::dispatchSimulatedMouseEvent(const AtomicString& eventType,
- PassRefPtr<Event> underlyingEvent)
-{
- ASSERT(!eventDispatchForbidden());
-
- 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();
- }
-
- // 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);
+ return EventDispatcher::dispatchEvent(this, MouseEventDispatchMediator(MouseEvent::create(eventType, document()->defaultView(), event, detail, relatedTarget)));
}
void Node::dispatchSimulatedClick(PassRefPtr<Event> event, bool sendMouseEvents, bool showPressedLook)
{
- if (!gNodesDispatchingSimulatedClicks)
- gNodesDispatchingSimulatedClicks = new HashSet<Node*>;
- else if (gNodesDispatchingSimulatedClicks->contains(this))
- return;
-
- gNodesDispatchingSimulatedClicks->add(this);
-
- // send mousedown and mouseup before the click, if requested
- if (sendMouseEvents)
- dispatchSimulatedMouseEvent(eventNames().mousedownEvent, event.get());
- setActive(true, showPressedLook);
- if (sendMouseEvents)
- dispatchSimulatedMouseEvent(eventNames().mouseupEvent, event.get());
- setActive(false);
-
- // always send click
- dispatchSimulatedMouseEvent(eventNames().clickEvent, event);
-
- gNodesDispatchingSimulatedClicks->remove(this);
+ EventDispatcher::dispatchSimulatedClick(this, event, sendMouseEvents, showPressedLook);
}
-// FIXME: Once https://bugs.webkit.org/show_bug.cgi?id=52963 lands, this should
-// be greatly improved. See https://bugs.webkit.org/show_bug.cgi?id=54025.
-static Node* pullOutOfShadow(Node* node)
+bool Node::dispatchWheelEvent(const PlatformWheelEvent& event)
{
- Node* outermostShadowBoundary = node;
- for (Node* n = node; n; n = n->parentOrHostNode()) {
- if (n->isShadowRoot())
- outermostShadowBoundary = n->parentOrHostNode();
- }
- return outermostShadowBoundary;
-}
-
-bool Node::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 != eventNames().mousemoveEvent;
-
- bool swallowEvent = false;
-
- // Attempting to dispatch with a non-EventTarget relatedTarget causes the relatedTarget to be silently ignored.
- RefPtr<Node> relatedTarget = pullOutOfShadow(relatedTargetArg);
-
- int adjustedPageX = pageX;
- int adjustedPageY = pageY;
- if (Frame* frame = document()->frame()) {
- float pageZoom = frame->pageZoomFactor();
- if (pageZoom != 1.0f) {
- // Adjust our pageX and pageY to account for the page zoom.
- adjustedPageX = lroundf(pageX / pageZoom);
- adjustedPageY = lroundf(pageY / pageZoom);
- }
- }
-
- RefPtr<MouseEvent> mouseEvent = MouseEvent::create(eventType,
- true, cancelable, document()->defaultView(),
- detail, screenX, screenY, adjustedPageX, adjustedPageY,
- ctrlKey, altKey, shiftKey, metaKey, button,
- relatedTarget, 0, isSimulated);
- mouseEvent->setUnderlyingEvent(underlyingEvent.get());
- mouseEvent->setAbsoluteLocation(IntPoint(pageX, pageY));
-
- dispatchEvent(mouseEvent);
- 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 == eventNames().clickEvent && detail == 2) {
- RefPtr<Event> doubleClickEvent = MouseEvent::create(eventNames().dblclickEvent,
- true, cancelable, document()->defaultView(),
- detail, screenX, screenY, adjustedPageX, adjustedPageY,
- ctrlKey, altKey, shiftKey, metaKey, button,
- relatedTarget, 0, isSimulated);
- doubleClickEvent->setUnderlyingEvent(underlyingEvent.get());
- if (defaultHandled)
- doubleClickEvent->setDefaultHandled();
- dispatchEvent(doubleClickEvent);
- if (doubleClickEvent->defaultHandled() || doubleClickEvent->defaultPrevented())
- swallowEvent = true;
- }
-
- return swallowEvent;
-}
-
-void Node::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());
-
- int adjustedPageX = pos.x();
- int adjustedPageY = pos.y();
- if (Frame* frame = document()->frame()) {
- float pageZoom = frame->pageZoomFactor();
- if (pageZoom != 1.0f) {
- // Adjust our pageX and pageY to account for the page zoom.
- adjustedPageX = lroundf(pos.x() / pageZoom);
- adjustedPageY = lroundf(pos.y() / pageZoom);
- }
- }
-
- WheelEvent::Granularity granularity;
- switch (e.granularity()) {
- case ScrollByPageWheelEvent:
- granularity = WheelEvent::Page;
- break;
- case ScrollByPixelWheelEvent:
- default:
- granularity = WheelEvent::Pixel;
- break;
- }
-
- RefPtr<WheelEvent> we = WheelEvent::create(e.wheelTicksX(), e.wheelTicksY(), e.deltaX(), e.deltaY(), granularity,
- document()->defaultView(), e.globalX(), e.globalY(), adjustedPageX, adjustedPageY,
- e.ctrlKey(), e.altKey(), e.shiftKey(), e.metaKey());
-
- we->setAbsoluteLocation(IntPoint(pos.x(), pos.y()));
-
- if (!dispatchEvent(we) || we->defaultHandled())
- e.accept();
-
- we.release();
+ return EventDispatcher::dispatchEvent(this, WheelEventDispatchMediator(event, document()->defaultView()));
}
void Node::dispatchFocusEvent()
@@ -3076,12 +2804,12 @@ void Node::dispatchBlurEvent()
dispatchEvent(Event::create(eventNames().blurEvent, false, false));
}
-void Node::dispatchChangeEvents()
+void Node::dispatchChangeEvent()
{
dispatchEvent(Event::create(eventNames().changeEvent, true, false));
}
-void Node::dispatchInputEvents()
+void Node::dispatchInputEvent()
{
dispatchEvent(Event::create(eventNames().inputEvent, true, false));
}
@@ -3143,7 +2871,7 @@ void Node::defaultEventHandler(Event* event)
if (Frame* frame = document()->frame())
frame->eventHandler()->defaultWheelEventHandler(startNode, wheelEvent);
} else if (event->type() == eventNames().webkitEditableContentChangedEvent) {
- dispatchInputEvents();
+ dispatchInputEvent();
}
}
diff --git a/Source/WebCore/dom/Node.h b/Source/WebCore/dom/Node.h
index 7ef7e80..1fe30ad 100644
--- a/Source/WebCore/dom/Node.h
+++ b/Source/WebCore/dom/Node.h
@@ -53,6 +53,7 @@ class EventContext;
class EventListener;
class FloatPoint;
class Frame;
+class InputElement;
class IntRect;
class KeyboardEvent;
class NSResolver;
@@ -70,7 +71,11 @@ class RenderBox;
class RenderBoxModelObject;
class RenderObject;
class RenderStyle;
+#if ENABLE(SVG)
+class SVGUseElement;
+#endif
class TagNodeList;
+class TreeScope;
typedef int ExceptionCode;
@@ -86,13 +91,10 @@ enum StyleChangeType {
SyntheticStyleChange = 3 << nodeStyleChangeShift
};
-enum EventDispatchBehavior {
- RetargetEvent,
- StayInsideShadowDOM
-};
-
class Node : public EventTarget, public TreeShared<ContainerNode>, public ScriptWrappable {
friend class Document;
+ friend class TreeScope;
+
public:
enum NodeType {
ELEMENT_NODE = 1,
@@ -192,6 +194,10 @@ public:
bool isHTMLElement() const { return getFlag(IsHTMLFlag); }
bool isSVGElement() const { return getFlag(IsSVGFlag); }
+ virtual bool isSVGShadowRoot() const { return false; }
+#if ENABLE(SVG)
+ SVGUseElement* svgShadowHost() const;
+#endif
#if ENABLE(WML)
virtual bool isWMLElement() const { return false; }
@@ -200,6 +206,7 @@ public:
#endif
virtual bool isMediaControlElement() const { return false; }
+ virtual bool isMediaControls() const { return false; }
bool isStyledElement() const { return getFlag(IsStyledElementFlag); }
virtual bool isFrameOwnerElement() const { return false; }
virtual bool isAttributeNode() const { return false; }
@@ -207,12 +214,16 @@ public:
virtual bool isCharacterDataNode() const { return false; }
bool isDocumentNode() const;
bool isShadowRoot() const { return getFlag(IsShadowRootFlag); }
+ // FIXME: Remove this when all shadow roots are ShadowRoots.
+ virtual bool isShadowBoundary() const { return false; }
+ virtual bool canHaveLightChildRendererWithShadow() const { return false; }
+
Node* shadowAncestorNode();
Node* shadowTreeRootNode();
bool isInShadowTree();
- // Node's parent or shadow tree host.
+ // Node's parent, shadow tree host, or SVG use.
ContainerNode* parentOrHostNode() const;
- // Use when it's guaranteed to that shadowHost is 0.
+ // Use when it's guaranteed to that shadowHost is 0 and svgShadowHost is 0.
ContainerNode* parentNodeGuaranteedHostFree() const;
Element* shadowHost() const;
@@ -224,9 +235,6 @@ public:
// Returns the enclosing event parent node (or self) that, when clicked, would trigger a navigation.
Node* enclosingLinkEventParentOrSelf();
- // Node ancestors when concerned about event flow.
- void getEventAncestors(Vector<EventContext>& ancestors, EventTarget*, EventDispatchBehavior = RetargetEvent);
-
bool isBlockFlow() const;
bool isBlockFlowOrBlockTable() const;
@@ -326,8 +334,10 @@ public:
virtual bool isKeyboardFocusable(KeyboardEvent*) const;
virtual bool isMouseFocusable() const;
- virtual bool isContentEditable() const;
- virtual bool isContentRichlyEditable() const;
+ bool isContentEditable() const;
+
+ bool rendererIsEditable() const { return rendererIsEditable(Editable); }
+ bool rendererIsRichlyEditable() const { return rendererIsEditable(RichlyEditable); }
virtual bool shouldUseInputMethod() const;
virtual IntRect getRect() const;
IntRect renderRect(bool* isReplaced);
@@ -354,12 +364,14 @@ public:
return m_document;
}
- // Do not use this method to change the document of a node until after the node has been
- // removed from its previous document.
- void setDocument(Document*);
+ TreeScope* treeScope() const;
+
+ // Do not use this method to change the scope of a node until after the node has been
+ // removed from its previous scope. Do not use to change documents.
+ void setTreeScope(TreeScope*);
// Used by the basic DOM methods (e.g., appendChild()).
- void setDocumentRecursively(Document*);
+ void setTreeScopeRecursively(TreeScope*);
// Returns true if this node is associated with a document and is in its associated document's
// node tree, false otherwise.
@@ -370,7 +382,7 @@ public:
}
bool isReadOnlyNode() const { return nodeType() == ENTITY_REFERENCE_NODE; }
- virtual bool childTypeAllowed(NodeType) { return false; }
+ virtual bool childTypeAllowed(NodeType) const { return false; }
unsigned childNodeCount() const;
Node* childNode(unsigned index) const;
@@ -449,6 +461,7 @@ public:
virtual bool rendererIsNeeded(RenderStyle*);
virtual bool childShouldCreateRenderer(Node*) const { return true; }
virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
+ ContainerNode* parentNodeForRenderingAndStyle() const;
// Wrapper for nodes that don't have a renderer, but still cache the style (like HTMLOptionElement).
RenderStyle* renderStyle() const;
@@ -529,6 +542,8 @@ public:
virtual Node* toNode() { return this; }
+ virtual InputElement* toInputElement();
+
virtual ScriptExecutionContext* scriptExecutionContext() const;
virtual bool addEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture);
@@ -543,25 +558,19 @@ public:
bool dispatchEvent(PassRefPtr<Event>);
void dispatchScopedEvent(PassRefPtr<Event>);
- bool dispatchGenericEvent(PassRefPtr<Event>);
virtual void handleLocalEvents(Event*);
void dispatchSubtreeModifiedEvent();
void dispatchUIEvent(const AtomicString& eventType, int detail, PassRefPtr<Event> underlyingEvent);
bool dispatchKeyEvent(const PlatformKeyboardEvent&);
- void dispatchWheelEvent(PlatformWheelEvent&);
+ bool dispatchWheelEvent(const 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, Node* relatedTarget, PassRefPtr<Event> underlyingEvent);
- void dispatchSimulatedMouseEvent(const AtomicString& eventType, PassRefPtr<Event> underlyingEvent);
void dispatchSimulatedClick(PassRefPtr<Event> underlyingEvent, bool sendMouseEvents = false, bool showPressedLook = true);
virtual void dispatchFocusEvent();
virtual void dispatchBlurEvent();
- virtual void dispatchChangeEvents();
- virtual void dispatchInputEvents();
+ virtual void dispatchChangeEvent();
+ virtual void dispatchInputEvent();
// Perform the default action for an event.
virtual void defaultEventHandler(Event*);
@@ -576,17 +585,6 @@ public:
virtual EventTargetData* eventTargetData();
virtual EventTargetData* ensureEventTargetData();
-#if USE(JSC)
- void markCachedNodeLists(JSC::MarkStack& markStack, JSC::JSGlobalData& globalData)
- {
- // NodeLists may be present. If so, they need to be marked.
- if (!hasRareData())
- return;
-
- markCachedNodeListsSlow(markStack, globalData);
- }
-#endif
-
private:
enum NodeFlags {
IsTextFlag = 1,
@@ -651,6 +649,11 @@ protected:
};
Node(Document*, ConstructionType);
+ // Do not use this method to change the document of a node until after the node has been
+ // removed from its previous document.
+ void setDocument(Document*);
+ void setDocumentRecursively(Document*);
+
virtual void willMoveToNewOwnerDocument();
virtual void didMoveToNewOwnerDocument();
@@ -664,9 +667,8 @@ protected:
NodeRareData* ensureRareData();
private:
-#if USE(JSC)
- void markCachedNodeListsSlow(JSC::MarkStack&, JSC::JSGlobalData&);
-#endif
+ enum EditableLevel { Editable, RichlyEditable };
+ bool rendererIsEditable(EditableLevel) const;
void setStyleChange(StyleChangeType);
@@ -738,7 +740,7 @@ inline void addSubresourceURL(ListHashSet<KURL>& urls, const KURL& url)
inline ContainerNode* Node::parentNode() const
{
- return getFlag(IsShadowRootFlag) ? 0 : parent();
+ return getFlag(IsShadowRootFlag) || isSVGShadowRoot() ? 0 : parent();
}
inline ContainerNode* Node::parentOrHostNode() const
@@ -748,7 +750,7 @@ inline ContainerNode* Node::parentOrHostNode() const
inline ContainerNode* Node::parentNodeGuaranteedHostFree() const
{
- ASSERT(!getFlag(IsShadowRootFlag));
+ ASSERT(!getFlag(IsShadowRootFlag) && !isSVGShadowRoot());
return parentOrHostNode();
}
diff --git a/Source/WebCore/dom/NodeFilter.h b/Source/WebCore/dom/NodeFilter.h
index 5ce2866..d6e47fb 100644
--- a/Source/WebCore/dom/NodeFilter.h
+++ b/Source/WebCore/dom/NodeFilter.h
@@ -70,15 +70,22 @@ namespace WebCore {
return adoptRef(new NodeFilter(condition));
}
+ static PassRefPtr<NodeFilter> create()
+ {
+ return adoptRef(new NodeFilter());
+ }
+
short acceptNode(ScriptState*, Node*) const;
- void markAggregate(JSC::MarkStack& markStack) { m_condition->markAggregate(markStack); };
// Do not call these functions. They are just scaffolding to support the Objective-C bindings.
// They operate in the main thread normal world, and they swallow JS exceptions.
short acceptNode(Node* node) const { return acceptNode(scriptStateFromNode(mainThreadNormalWorld(), node), node); }
+
+ void setCondition(PassRefPtr<NodeFilterCondition> condition) { ASSERT(!m_condition); m_condition = condition; }
private:
NodeFilter(PassRefPtr<NodeFilterCondition> condition) : m_condition(condition) { }
+ NodeFilter() {}
RefPtr<NodeFilterCondition> m_condition;
};
diff --git a/Source/WebCore/dom/NodeList.h b/Source/WebCore/dom/NodeList.h
index d4e18aa..7639d37 100644
--- a/Source/WebCore/dom/NodeList.h
+++ b/Source/WebCore/dom/NodeList.h
@@ -39,6 +39,9 @@ namespace WebCore {
virtual unsigned length() const = 0;
virtual Node* item(unsigned index) const = 0;
virtual Node* itemWithName(const AtomicString&) const = 0;
+
+ // Other methods (not part of DOM)
+ virtual bool isDynamicNodeList() const { return false; }
};
} // namespace WebCore
diff --git a/Source/WebCore/dom/NodeList.idl b/Source/WebCore/dom/NodeList.idl
index edb2dc7..b751f66 100644
--- a/Source/WebCore/dom/NodeList.idl
+++ b/Source/WebCore/dom/NodeList.idl
@@ -21,6 +21,7 @@
module core {
interface [
+ CustomToJS,
HasIndexGetter,
HasNameGetter,
CustomCall
diff --git a/Source/WebCore/dom/NodeRareData.h b/Source/WebCore/dom/NodeRareData.h
index badc4e1..ac05d3e 100644
--- a/Source/WebCore/dom/NodeRareData.h
+++ b/Source/WebCore/dom/NodeRareData.h
@@ -34,6 +34,8 @@
namespace WebCore {
+class TreeScope;
+
struct NodeListsNodeData {
WTF_MAKE_NONCOPYABLE(NodeListsNodeData); WTF_MAKE_FAST_ALLOCATED;
public:
@@ -73,7 +75,8 @@ class NodeRareData {
WTF_MAKE_NONCOPYABLE(NodeRareData); WTF_MAKE_FAST_ALLOCATED;
public:
NodeRareData()
- : m_tabIndex(0)
+ : m_treeScope(0)
+ , m_tabIndex(0)
, m_tabIndexWasSetExplicitly(false)
, m_isFocused(false)
, m_needsFocusAppearanceUpdateSoonAfterAttach(false)
@@ -96,11 +99,14 @@ public:
{
return rareDataMap().get(node);
}
+
+ TreeScope* treeScope() const { return m_treeScope; }
+ void setTreeScope(TreeScope* treeScope) { m_treeScope = treeScope; }
void clearNodeLists() { m_nodeLists.clear(); }
void setNodeLists(PassOwnPtr<NodeListsNodeData> lists) { m_nodeLists = lists; }
NodeListsNodeData* nodeLists() const { return m_nodeLists.get(); }
-
+
short tabIndex() const { return m_tabIndex; }
void setTabIndexExplicitly(short index) { m_tabIndex = index; m_tabIndexWasSetExplicitly = true; }
bool tabIndexSetExplicitly() const { return m_tabIndexWasSetExplicitly; }
@@ -123,6 +129,7 @@ protected:
void setNeedsFocusAppearanceUpdateSoonAfterAttach(bool needs) { m_needsFocusAppearanceUpdateSoonAfterAttach = needs; }
private:
+ TreeScope* m_treeScope;
OwnPtr<NodeListsNodeData> m_nodeLists;
OwnPtr<EventTargetData> m_eventTargetData;
short m_tabIndex;
diff --git a/Source/WebCore/dom/NodeRenderStyle.h b/Source/WebCore/dom/NodeRenderStyle.h
index 3a67e02..1a2d2c3 100644
--- a/Source/WebCore/dom/NodeRenderStyle.h
+++ b/Source/WebCore/dom/NodeRenderStyle.h
@@ -33,7 +33,11 @@ namespace WebCore {
inline RenderStyle* Node::renderStyle() const
{
- return m_renderer ? m_renderer->style() : nonRendererRenderStyle();
+ // Using a ternary here confuses the Solaris Studio 12/12.1/12.2 compilers:
+ // Bug is CR 6569194, "Problem with question operator binding in inline function"
+ if (m_renderer)
+ return m_renderer->style();
+ return nonRendererRenderStyle();
}
}
diff --git a/Source/WebCore/dom/Notation.cpp b/Source/WebCore/dom/Notation.cpp
index 4b3ab28..f62e630 100644
--- a/Source/WebCore/dom/Notation.cpp
+++ b/Source/WebCore/dom/Notation.cpp
@@ -49,7 +49,7 @@ PassRefPtr<Node> Notation::cloneNode(bool /*deep*/)
return 0;
}
-bool Notation::childTypeAllowed(NodeType)
+bool Notation::childTypeAllowed(NodeType) const
{
return false;
}
diff --git a/Source/WebCore/dom/Notation.h b/Source/WebCore/dom/Notation.h
index 547c9e7..b2155ba 100644
--- a/Source/WebCore/dom/Notation.h
+++ b/Source/WebCore/dom/Notation.h
@@ -39,7 +39,7 @@ private:
virtual String nodeName() const;
virtual NodeType nodeType() const;
virtual PassRefPtr<Node> cloneNode(bool deep);
- virtual bool childTypeAllowed(NodeType);
+ virtual bool childTypeAllowed(NodeType) const;
String m_name;
String m_publicId;
diff --git a/Source/WebCore/dom/Position.cpp b/Source/WebCore/dom/Position.cpp
index 473610a..1b58a42 100644
--- a/Source/WebCore/dom/Position.cpp
+++ b/Source/WebCore/dom/Position.cpp
@@ -46,7 +46,7 @@ using namespace HTMLNames;
static Node* nextRenderedEditable(Node* node)
{
while ((node = node->nextLeafNode())) {
- if (!node->isContentEditable())
+ if (!node->rendererIsEditable())
continue;
RenderObject* renderer = node->renderer();
if (!renderer)
@@ -60,7 +60,7 @@ static Node* nextRenderedEditable(Node* node)
static Node* previousRenderedEditable(Node* node)
{
while ((node = node->previousLeafNode())) {
- if (!node->isContentEditable())
+ if (!node->rendererIsEditable())
continue;
RenderObject* renderer = node->renderer();
if (!renderer)
@@ -94,11 +94,13 @@ Position::Position(PassRefPtr<Node> anchorNode, int offset, AnchorType anchorTyp
, m_anchorType(anchorType)
, m_isLegacyEditingPosition(false)
{
+ ASSERT(!m_anchorNode || !editingIgnoresContent(m_anchorNode.get()));
ASSERT(anchorType == PositionIsOffsetInAnchor);
}
void Position::moveToPosition(PassRefPtr<Node> node, int offset)
{
+ ASSERT(!editingIgnoresContent(node.get()));
ASSERT(anchorType() == PositionIsOffsetInAnchor || m_isLegacyEditingPosition);
m_anchorNode = node;
m_offset = offset;
@@ -161,12 +163,12 @@ Position Position::parentAnchoredEquivalent() const
return Position();
// FIXME: This should only be necessary for legacy positions, but is also needed for positions before and after Tables
- if (m_offset <= 0) {
+ if (m_offset <= 0 && m_anchorType != PositionIsAfterAnchor) {
if (m_anchorNode->parentNode() && (editingIgnoresContent(m_anchorNode.get()) || isTableElement(m_anchorNode.get())))
return positionInParentBeforeNode(m_anchorNode.get());
- return Position(m_anchorNode, 0, PositionIsOffsetInAnchor);
+ return firstPositionInOrBeforeNode(m_anchorNode.get());
}
- if (!m_anchorNode->offsetInCharacters() && static_cast<unsigned>(m_offset) == m_anchorNode->childNodeCount()
+ if (!m_anchorNode->offsetInCharacters() && (m_anchorType == PositionIsAfterAnchor || static_cast<unsigned>(m_offset) == m_anchorNode->childNodeCount())
&& (editingIgnoresContent(m_anchorNode.get()) || isTableElement(m_anchorNode.get()))) {
return positionInParentAfterNode(m_anchorNode.get());
}
@@ -240,15 +242,15 @@ Position Position::previous(PositionMoveType moveType) const
Node* n = deprecatedNode();
if (!n)
return *this;
-
- int o = m_offset;
+
+ int o = deprecatedEditingOffset();
// 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 lastDeepEditingPositionForNode(child);
+ return lastPositionInOrAfterNode(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.
@@ -279,15 +281,15 @@ Position Position::next(PositionMoveType moveType) const
Node* n = deprecatedNode();
if (!n)
return *this;
-
- int o = m_offset;
+
+ int o = deprecatedEditingOffset();
// 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 < lastOffsetForEditing(n))) {
if (child)
- return firstDeepEditingPositionForNode(child);
+ return firstPositionInOrBeforeNode(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.
@@ -323,14 +325,14 @@ bool Position::atFirstEditingPositionForNode() const
{
if (isNull())
return true;
- return m_offset <= 0;
+ return m_anchorType == PositionIsBeforeAnchor || m_offset <= 0;
}
bool Position::atLastEditingPositionForNode() const
{
if (isNull())
return true;
- return m_offset >= lastOffsetForEditing(deprecatedNode());
+ return m_anchorType == PositionIsAfterAnchor || m_offset >= lastOffsetForEditing(deprecatedNode());
}
// A position is considered at editing boundary if one of the following is true:
@@ -343,15 +345,15 @@ bool Position::atLastEditingPositionForNode() const
bool Position::atEditingBoundary() const
{
Position nextPosition = downstream(CanCrossEditingBoundary);
- if (atFirstEditingPositionForNode() && nextPosition.isNotNull() && !nextPosition.deprecatedNode()->isContentEditable())
+ if (atFirstEditingPositionForNode() && nextPosition.isNotNull() && !nextPosition.deprecatedNode()->rendererIsEditable())
return true;
Position prevPosition = upstream(CanCrossEditingBoundary);
- if (atLastEditingPositionForNode() && prevPosition.isNotNull() && !prevPosition.deprecatedNode()->isContentEditable())
+ if (atLastEditingPositionForNode() && prevPosition.isNotNull() && !prevPosition.deprecatedNode()->rendererIsEditable())
return true;
- return nextPosition.isNotNull() && !nextPosition.deprecatedNode()->isContentEditable()
- && prevPosition.isNotNull() && !prevPosition.deprecatedNode()->isContentEditable();
+ return nextPosition.isNotNull() && !nextPosition.deprecatedNode()->rendererIsEditable()
+ && prevPosition.isNotNull() && !prevPosition.deprecatedNode()->rendererIsEditable();
}
Node* Position::parentEditingBoundary() const
@@ -364,7 +366,7 @@ Node* Position::parentEditingBoundary() const
return 0;
Node* boundary = m_anchorNode.get();
- while (boundary != documentElement && boundary->parentNode() && m_anchorNode->isContentEditable() == boundary->parentNode()->isContentEditable())
+ while (boundary != documentElement && boundary->parentNode() && m_anchorNode->rendererIsEditable() == boundary->parentNode()->rendererIsEditable())
boundary = boundary->parentNode();
return boundary;
@@ -523,17 +525,17 @@ Position Position::upstream(EditingBoundaryCrossingRule rule) const
// FIXME: PositionIterator should respect Before and After positions.
PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? Position(m_anchorNode, caretMaxOffset(m_anchorNode.get())) : *this;
PositionIterator currentPos = lastVisible;
- bool startEditable = startNode->isContentEditable();
+ bool startEditable = startNode->rendererIsEditable();
Node* lastNode = startNode;
bool boundaryCrossed = false;
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().
+ // to avoid the expense of computing rendererIsEditable().
if (currentNode != lastNode) {
// Don't change editability.
- bool currentEditable = currentNode->isContentEditable();
+ bool currentEditable = currentNode->rendererIsEditable();
if (startEditable != currentEditable) {
if (rule == CannotCrossEditingBoundary)
break;
@@ -569,7 +571,7 @@ Position Position::upstream(EditingBoundaryCrossingRule rule) const
// Return position after tables and nodes which have content that can be ignored.
if (editingIgnoresContent(currentNode) || isTableElement(currentNode)) {
if (currentPos.atEndOfNode())
- return lastDeepEditingPositionForNode(currentNode);
+ return positionAfterNode(currentNode);
continue;
}
@@ -645,17 +647,17 @@ Position Position::downstream(EditingBoundaryCrossingRule rule) const
// FIXME: PositionIterator should respect Before and After positions.
PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? Position(m_anchorNode, caretMaxOffset(m_anchorNode.get())) : *this;
PositionIterator currentPos = lastVisible;
- bool startEditable = startNode->isContentEditable();
+ bool startEditable = startNode->rendererIsEditable();
Node* lastNode = startNode;
bool boundaryCrossed = false;
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().
+ // to avoid the expense of computing rendererIsEditable().
if (currentNode != lastNode) {
// Don't change editability.
- bool currentEditable = currentNode->isContentEditable();
+ bool currentEditable = currentNode->rendererIsEditable();
if (startEditable != currentEditable) {
if (rule == CannotCrossEditingBoundary)
break;
@@ -781,7 +783,8 @@ bool Position::isCandidate() const
return false;
if (renderer->isBR())
- return !m_offset && !nodeIsUserSelectNone(deprecatedNode()->parentNode());
+ // FIXME: The condition should be m_anchorType == PositionIsBeforeAnchor, but for now we still need to support legacy positions.
+ return !m_offset && m_anchorType != PositionIsAfterAnchor && !nodeIsUserSelectNone(deprecatedNode()->parentNode());
if (renderer->isText())
return !nodeIsUserSelectNone(deprecatedNode()) && inRenderedText();
@@ -796,10 +799,10 @@ bool Position::isCandidate() const
if (toRenderBlock(renderer)->height() || m_anchorNode->hasTagName(bodyTag)) {
if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer))
return atFirstEditingPositionForNode() && !Position::nodeIsUserSelectNone(deprecatedNode());
- return m_anchorNode->isContentEditable() && !Position::nodeIsUserSelectNone(deprecatedNode()) && atEditingBoundary();
+ return m_anchorNode->rendererIsEditable() && !Position::nodeIsUserSelectNone(deprecatedNode()) && atEditingBoundary();
}
} else
- return m_anchorNode->isContentEditable() && !Position::nodeIsUserSelectNone(deprecatedNode()) && atEditingBoundary();
+ return m_anchorNode->rendererIsEditable() && !Position::nodeIsUserSelectNone(deprecatedNode()) && atEditingBoundary();
return false;
}
@@ -982,7 +985,7 @@ Position Position::trailingWhitespacePosition(EAffinity, bool considerNonCollaps
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 (!isEndOfParagraph(v) && v.next(CannotCrossEditingBoundary).isNotNull())
if (considerNonCollapsibleWhitespace ? (isSpaceOrNewline(c) || c == noBreakSpace) : isCollapsibleWhitespace(c))
return *this;
@@ -1053,7 +1056,7 @@ static Position upstreamIgnoringEditingBoundaries(Position position)
void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDirection, InlineBox*& inlineBox, int& caretOffset) const
{
- caretOffset = m_offset;
+ caretOffset = deprecatedEditingOffset();
RenderObject* renderer = deprecatedNode()->renderer();
if (!renderer->isText()) {
diff --git a/Source/WebCore/dom/Position.h b/Source/WebCore/dom/Position.h
index 4e1eff4..a72664e 100644
--- a/Source/WebCore/dom/Position.h
+++ b/Source/WebCore/dom/Position.h
@@ -133,6 +133,7 @@ public:
// These can be either inside or just before/after the node, depending on
// if the node is ignored by editing or not.
+ // FIXME: These should go away. They only make sense for legacy positions.
bool atFirstEditingPositionForNode() const;
bool atLastEditingPositionForNode() const;
@@ -196,7 +197,7 @@ inline bool operator==(const Position& a, const Position& b)
{
// FIXME: In <div><img></div> [div, 0] != [img, 0] even though most of the
// editing code will treat them as identical.
- return a.anchorNode() == b.anchorNode() && a.deprecatedEditingOffset() == b.deprecatedEditingOffset();
+ return a.anchorNode() == b.anchorNode() && a.deprecatedEditingOffset() == b.deprecatedEditingOffset() && a.anchorType() == b.anchorType();
}
inline bool operator!=(const Position& a, const Position& b)
diff --git a/Source/WebCore/dom/PositionIterator.cpp b/Source/WebCore/dom/PositionIterator.cpp
index 5de9d9d..6821308 100644
--- a/Source/WebCore/dom/PositionIterator.cpp
+++ b/Source/WebCore/dom/PositionIterator.cpp
@@ -38,10 +38,13 @@ PositionIterator::operator Position() const
{
if (m_nodeAfterPositionInAnchor) {
ASSERT(m_nodeAfterPositionInAnchor->parentNode() == m_anchorNode);
+ // FIXME: This check is inadaquete because any ancestor could be ignored by editing
+ if (editingIgnoresContent(m_nodeAfterPositionInAnchor->parentNode()))
+ return positionBeforeNode(m_anchorNode);
return positionInParentBeforeNode(m_nodeAfterPositionInAnchor);
}
if (m_anchorNode->hasChildNodes())
- return lastDeepEditingPositionForNode(m_anchorNode);
+ return lastPositionInOrAfterNode(m_anchorNode);
return Position(m_anchorNode, m_offsetInAnchor);
}
@@ -166,7 +169,7 @@ bool PositionIterator::isCandidate() const
if (toRenderBlock(renderer)->height() || m_anchorNode->hasTagName(bodyTag)) {
if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer))
return atStartOfNode() && !Position::nodeIsUserSelectNone(m_anchorNode);
- return m_anchorNode->isContentEditable() && !Position::nodeIsUserSelectNone(m_anchorNode) && Position(*this).atEditingBoundary();
+ return m_anchorNode->rendererIsEditable() && !Position::nodeIsUserSelectNone(m_anchorNode) && Position(*this).atEditingBoundary();
}
}
diff --git a/Source/WebCore/dom/ProcessingInstruction.cpp b/Source/WebCore/dom/ProcessingInstruction.cpp
index ae0e40d..7135644 100644
--- a/Source/WebCore/dom/ProcessingInstruction.cpp
+++ b/Source/WebCore/dom/ProcessingInstruction.cpp
@@ -101,7 +101,7 @@ PassRefPtr<Node> ProcessingInstruction::cloneNode(bool /*deep*/)
}
// DOM Section 1.1.1
-bool ProcessingInstruction::childTypeAllowed(NodeType)
+bool ProcessingInstruction::childTypeAllowed(NodeType) const
{
return false;
}
diff --git a/Source/WebCore/dom/ProcessingInstruction.h b/Source/WebCore/dom/ProcessingInstruction.h
index 8619070..fd98566 100644
--- a/Source/WebCore/dom/ProcessingInstruction.h
+++ b/Source/WebCore/dom/ProcessingInstruction.h
@@ -69,7 +69,7 @@ private:
virtual String nodeValue() const;
virtual void setNodeValue(const String&, ExceptionCode&);
virtual PassRefPtr<Node> cloneNode(bool deep);
- virtual bool childTypeAllowed(NodeType);
+ virtual bool childTypeAllowed(NodeType) const;
virtual bool offsetInCharacters() const;
virtual int maxCharacterOffset() const;
diff --git a/Source/WebCore/dom/QualifiedName.h b/Source/WebCore/dom/QualifiedName.h
index cb95f20..01eaebb 100644
--- a/Source/WebCore/dom/QualifiedName.h
+++ b/Source/WebCore/dom/QualifiedName.h
@@ -113,7 +113,7 @@ inline bool operator!=(const QualifiedName& q, const AtomicString& a) { return a
inline unsigned hashComponents(const QualifiedNameComponents& buf)
{
- return WTF::StringHasher::createBlobHash<sizeof(QualifiedNameComponents)>(&buf);
+ return StringHasher::hashMemory<sizeof(QualifiedNameComponents)>(&buf);
}
struct QualifiedNameHash {
@@ -141,11 +141,9 @@ namespace WTF {
typedef WebCore::QualifiedNameHash Hash;
};
- template<> struct HashTraits<WebCore::QualifiedName> : GenericHashTraits<WebCore::QualifiedName> {
+ template<> struct HashTraits<WebCore::QualifiedName> : SimpleClassHashTraits<WebCore::QualifiedName> {
static const bool emptyValueIsZero = false;
static WebCore::QualifiedName emptyValue() { return WebCore::QualifiedName(nullAtom, nullAtom, nullAtom); }
- static void constructDeletedValue(WebCore::QualifiedName& slot) { new (&slot) WebCore::QualifiedName(WTF::HashTableDeletedValue); }
- static bool isDeletedValue(const WebCore::QualifiedName& slot) { return slot.isHashTableDeletedValue(); }
};
}
diff --git a/Source/WebCore/dom/Range.cpp b/Source/WebCore/dom/Range.cpp
index a0370fa..469a94a 100644
--- a/Source/WebCore/dom/Range.cpp
+++ b/Source/WebCore/dom/Range.cpp
@@ -224,8 +224,10 @@ void Range::setStart(PassRefPtr<Node> refNode, int offset, ExceptionCode& ec)
if (startRootContainer != endRootContainer)
collapse(true, ec);
// check if new start after end
- else if (compareBoundaryPoints(m_start, m_end) > 0)
+ else if (compareBoundaryPoints(m_start, m_end, ec) > 0) {
+ ASSERT(!ec);
collapse(true, ec);
+ }
}
void Range::setEnd(PassRefPtr<Node> refNode, int offset, ExceptionCode& ec)
@@ -262,8 +264,10 @@ void Range::setEnd(PassRefPtr<Node> refNode, int offset, ExceptionCode& ec)
if (startRootContainer != endRootContainer)
collapse(false, ec);
// check if new end before start
- if (compareBoundaryPoints(m_start, m_end) > 0)
+ if (compareBoundaryPoints(m_start, m_end, ec) > 0) {
+ ASSERT(!ec);
collapse(false, ec);
+ }
}
void Range::collapse(bool toStart, ExceptionCode& ec)
@@ -306,8 +310,8 @@ bool Range::isPointInRange(Node* refNode, int offset, ExceptionCode& ec)
if (ec)
return false;
- return compareBoundaryPoints(refNode, offset, m_start.container(), m_start.offset()) >= 0
- && compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offset()) <= 0;
+ return compareBoundaryPoints(refNode, offset, m_start.container(), m_start.offset(), ec) >= 0 && !ec
+ && compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offset(), ec) <= 0 && !ec;
}
short Range::comparePoint(Node* refNode, int offset, ExceptionCode& ec) const
@@ -337,11 +341,14 @@ short Range::comparePoint(Node* refNode, int offset, ExceptionCode& ec) const
return 0;
// compare to start, and point comes before
- if (compareBoundaryPoints(refNode, offset, m_start.container(), m_start.offset()) < 0)
+ if (compareBoundaryPoints(refNode, offset, m_start.container(), m_start.offset(), ec) < 0)
return -1;
+ if (ec)
+ return 0;
+
// compare to end, and point comes after
- if (compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offset()) > 0)
+ if (compareBoundaryPoints(refNode, offset, m_end.container(), m_end.offset(), ec) > 0 && !ec)
return 1;
// point is in the middle of this range, or on the boundary points
@@ -433,20 +440,20 @@ short Range::compareBoundaryPoints(CompareHow how, const Range* sourceRange, Exc
switch (how) {
case START_TO_START:
- return compareBoundaryPoints(m_start, sourceRange->m_start);
+ return compareBoundaryPoints(m_start, sourceRange->m_start, ec);
case START_TO_END:
- return compareBoundaryPoints(m_end, sourceRange->m_start);
+ return compareBoundaryPoints(m_end, sourceRange->m_start, ec);
case END_TO_END:
- return compareBoundaryPoints(m_end, sourceRange->m_end);
+ return compareBoundaryPoints(m_end, sourceRange->m_end, ec);
case END_TO_START:
- return compareBoundaryPoints(m_start, sourceRange->m_end);
+ return compareBoundaryPoints(m_start, sourceRange->m_end, ec);
}
ec = SYNTAX_ERR;
return 0;
}
-short Range::compareBoundaryPoints(Node* containerA, int offsetA, Node* containerB, int offsetB)
+short Range::compareBoundaryPoints(Node* containerA, int offsetA, Node* containerB, int offsetB, ExceptionCode& ec)
{
ASSERT(containerA);
ASSERT(containerB);
@@ -507,8 +514,10 @@ short Range::compareBoundaryPoints(Node* containerA, int offsetA, Node* containe
// case 4: containers A & B are siblings, or children of siblings
// ### we need to do a traversal here instead
Node* commonAncestor = commonAncestorContainer(containerA, containerB);
- if (!commonAncestor)
+ if (!commonAncestor) {
+ ec = WRONG_DOCUMENT_ERR;
return 0;
+ }
Node* childA = containerA;
while (childA && childA->parentNode() != commonAncestor)
childA = childA->parentNode();
@@ -537,14 +546,15 @@ short Range::compareBoundaryPoints(Node* containerA, int offsetA, Node* containe
return 0;
}
-short Range::compareBoundaryPoints(const RangeBoundaryPoint& boundaryA, const RangeBoundaryPoint& boundaryB)
+short Range::compareBoundaryPoints(const RangeBoundaryPoint& boundaryA, const RangeBoundaryPoint& boundaryB, ExceptionCode& ec)
{
- return compareBoundaryPoints(boundaryA.container(), boundaryA.offset(), boundaryB.container(), boundaryB.offset());
+ return compareBoundaryPoints(boundaryA.container(), boundaryA.offset(), boundaryB.container(), boundaryB.offset(), ec);
}
bool Range::boundaryPointsValid() const
{
- return m_start.container() && compareBoundaryPoints(m_start, m_end) <= 0;
+ ExceptionCode ec = 0;
+ return m_start.container() && compareBoundaryPoints(m_start, m_end, ec) <= 0 && !ec;
}
void Range::deleteContents(ExceptionCode& ec)
@@ -932,13 +942,6 @@ void Range::insertNode(PassRefPtr<Node> prpNewNode, ExceptionCode& ec)
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_start.container()->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.
@@ -1423,13 +1426,6 @@ void Range::surroundContents(PassRefPtr<Node> passNewParent, ExceptionCode& ec)
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_start.container()->document()) {
- ec = WRONG_DOCUMENT_ERR;
- return;
- }
-
// Raise a HIERARCHY_REQUEST_ERR if m_start.container() doesn't accept children like newParent.
Node* parentOfNewParent = m_start.container();
@@ -1634,7 +1630,7 @@ void Range::textRects(Vector<IntRect>& rects, bool useSelectionHeight)
}
}
-void Range::textQuads(Vector<FloatQuad>& quads, bool useSelectionHeight)
+void Range::textQuads(Vector<FloatQuad>& quads, bool useSelectionHeight) const
{
Node* startContainer = m_start.container();
Node* endContainer = m_end.container();
@@ -1907,16 +1903,24 @@ PassRefPtr<ClientRect> Range::getBoundingClientRect() const
return rect.isEmpty() ? 0 : ClientRect::create(rect);
}
-static void adjustFloatQuadsForScrollAndAbsoluteZoom(Vector<FloatQuad>& quads, Document* document, RenderObject* renderer)
+static void adjustFloatQuadsForScrollAndAbsoluteZoomAndPageScale(Vector<FloatQuad>& quads, Document* document, RenderObject* renderer)
{
FrameView* view = document->view();
if (!view)
return;
+ float pageScale = 1;
+ if (Page* page = document->page()) {
+ if (Frame* frame = page->mainFrame())
+ pageScale = frame->pageScaleFactor();
+ }
+
IntRect visibleContentRect = view->visibleContentRect();
for (size_t i = 0; i < quads.size(); ++i) {
quads[i].move(-visibleContentRect.x(), -visibleContentRect.y());
adjustFloatQuadForAbsoluteZoom(quads[i], renderer);
+ if (pageScale != 1)
+ adjustFloatQuadForPageScale(quads[i], pageScale);
}
}
@@ -1938,7 +1942,7 @@ void Range::getBorderAndTextQuads(Vector<FloatQuad>& quads) const
if (RenderBoxModelObject* renderBoxModelObject = static_cast<Element*>(node)->renderBoxModelObject()) {
Vector<FloatQuad> elementQuads;
renderBoxModelObject->absoluteQuads(elementQuads);
- adjustFloatQuadsForScrollAndAbsoluteZoom(elementQuads, m_ownerDocument.get(), renderBoxModelObject);
+ adjustFloatQuadsForScrollAndAbsoluteZoomAndPageScale(elementQuads, m_ownerDocument.get(), renderBoxModelObject);
quads.append(elementQuads);
}
@@ -1951,7 +1955,7 @@ void Range::getBorderAndTextQuads(Vector<FloatQuad>& quads) const
Vector<FloatQuad> textQuads;
renderText->absoluteQuadsForRange(textQuads, startOffset, endOffset);
- adjustFloatQuadsForScrollAndAbsoluteZoom(textQuads, m_ownerDocument.get(), renderText);
+ adjustFloatQuadsForScrollAndAbsoluteZoomAndPageScale(textQuads, m_ownerDocument.get(), renderText);
quads.append(textQuads);
}
diff --git a/Source/WebCore/dom/Range.h b/Source/WebCore/dom/Range.h
index 5637b77..062ad67 100644
--- a/Source/WebCore/dom/Range.h
+++ b/Source/WebCore/dom/Range.h
@@ -69,8 +69,8 @@ public:
CompareResults compareNode(Node* refNode, ExceptionCode&) const;
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 RangeBoundaryPoint& boundaryA, const RangeBoundaryPoint& boundaryB);
+ static short compareBoundaryPoints(Node* containerA, int offsetA, Node* containerB, int offsetB, ExceptionCode&);
+ static short compareBoundaryPoints(const RangeBoundaryPoint& boundaryA, const RangeBoundaryPoint& boundaryB, ExceptionCode&);
bool boundaryPointsValid() const;
bool intersectsNode(Node* refNode, ExceptionCode&);
void deleteContents(ExceptionCode&);
@@ -109,7 +109,7 @@ public:
// Not transform-friendly
void textRects(Vector<IntRect>&, bool useSelectionHeight = false);
// Transform-friendly
- void textQuads(Vector<FloatQuad>&, bool useSelectionHeight = false);
+ void textQuads(Vector<FloatQuad>&, bool useSelectionHeight = false) const;
void getBorderAndTextQuads(Vector<FloatQuad>&) const;
FloatRect boundingRect() const;
diff --git a/Source/WebCore/dom/ScriptElement.cpp b/Source/WebCore/dom/ScriptElement.cpp
index 3bba9a0..55a7949 100644
--- a/Source/WebCore/dom/ScriptElement.cpp
+++ b/Source/WebCore/dom/ScriptElement.cpp
@@ -24,9 +24,9 @@
#include "config.h"
#include "ScriptElement.h"
-#include "AsyncScriptRunner.h"
#include "CachedScript.h"
#include "CachedResourceLoader.h"
+#include "ContentSecurityPolicy.h"
#include "Document.h"
#include "DocumentParser.h"
#include "Frame.h"
@@ -37,6 +37,7 @@
#include "MIMETypeRegistry.h"
#include "Page.h"
#include "ScriptController.h"
+#include "ScriptRunner.h"
#include "ScriptSourceCode.h"
#include "ScriptValue.h"
#include "Settings.h"
@@ -61,6 +62,8 @@ ScriptElement::ScriptElement(Element* element, bool parserInserted, bool already
, m_willBeParserExecuted(false)
, m_readyToBeParserExecuted(false)
, m_willExecuteWhenDocumentFinishedParsing(false)
+ , m_forceAsync(!parserInserted)
+ , m_willExecuteInOrder(false)
{
ASSERT(m_element);
}
@@ -96,6 +99,11 @@ void ScriptElement::handleSourceAttribute(const String& sourceUrl)
prepareScript(); // FIXME: Provide a real starting line number here.
}
+void ScriptElement::handleAsyncAttribute()
+{
+ m_forceAsync = false;
+}
+
// Helper function
static bool isLegacySupportedJavaScriptLanguage(const String& language)
{
@@ -159,7 +167,8 @@ bool ScriptElement::prepareScript(const TextPosition1& scriptStartPosition, Lega
} else
wasParserInserted = false;
- // FIXME: HTML5 spec says we should set forceAsync.
+ if (wasParserInserted && !asyncAttributeValue())
+ m_forceAsync = true;
// FIXME: HTML5 spec says we should check that all children are either comments or empty text nodes.
if (!hasSourceAttribute() && !m_element->firstChild())
@@ -171,8 +180,10 @@ bool ScriptElement::prepareScript(const TextPosition1& scriptStartPosition, Lega
if (!isScriptTypeSupported(supportLegacyTypes))
return false;
- if (wasParserInserted)
+ if (wasParserInserted) {
m_parserInserted = true;
+ m_forceAsync = false;
+ }
m_alreadyStarted = true;
@@ -187,6 +198,14 @@ bool ScriptElement::prepareScript(const TextPosition1& scriptStartPosition, Lega
if (!m_element->document()->frame()->script()->canExecuteScripts(AboutToExecuteScript))
return false;
+ // FIXME: This is non-standard. Remove this after https://bugs.webkit.org/show_bug.cgi?id=62412.
+ Node* ancestor = m_element->parentNode();
+ while (ancestor) {
+ if (ancestor->isSVGShadowRoot())
+ return false;
+ ancestor = ancestor->parentNode();
+ }
+
if (!isScriptForEventSupported())
return false;
@@ -207,6 +226,10 @@ bool ScriptElement::prepareScript(const TextPosition1& scriptStartPosition, Lega
else if (!hasSourceAttribute() && m_parserInserted && !m_element->document()->haveStylesheetsLoaded()) {
m_willBeParserExecuted = true;
m_readyToBeParserExecuted = true;
+ } else if (hasSourceAttribute() && !asyncAttributeValue() && !m_forceAsync) {
+ m_willExecuteInOrder = true;
+ m_element->document()->scriptRunner()->queueScriptForExecution(this, m_cachedScript, ScriptRunner::IN_ORDER_EXECUTION);
+ m_cachedScript->addClient(this);
} else if (hasSourceAttribute())
m_cachedScript->addClient(this);
else
@@ -217,9 +240,6 @@ bool ScriptElement::prepareScript(const TextPosition1& scriptStartPosition, Lega
bool ScriptElement::requestScript(const String& sourceUrl)
{
- if (!m_element->document()->contentSecurityPolicy()->canLoadExternalScriptFromSrc(sourceUrl))
- return false;
-
RefPtr<Document> originalDocument = m_element->document();
if (!m_element->dispatchBeforeLoadEvent(sourceUrl))
return false;
@@ -245,6 +265,9 @@ void ScriptElement::executeScript(const ScriptSourceCode& sourceCode)
if (sourceCode.isEmpty())
return;
+ if (!m_isExternalScript && !m_element->document()->contentSecurityPolicy()->allowInlineScript())
+ return;
+
RefPtr<Document> document = m_element->document();
ASSERT(document);
if (Frame* frame = document->frame()) {
@@ -286,7 +309,10 @@ void ScriptElement::notifyFinished(CachedResource* o)
{
ASSERT(!m_willBeParserExecuted);
ASSERT_UNUSED(o, o == m_cachedScript);
- m_element->document()->asyncScriptRunner()->executeScriptSoon(this, m_cachedScript);
+ if (m_willExecuteInOrder)
+ m_element->document()->scriptRunner()->notifyInOrderScriptReady();
+ else
+ m_element->document()->scriptRunner()->queueScriptForExecution(this, m_cachedScript, ScriptRunner::ASYNC_EXECUTION);
m_cachedScript = 0;
}
diff --git a/Source/WebCore/dom/ScriptElement.h b/Source/WebCore/dom/ScriptElement.h
index 79dff33..9ce66e5 100644
--- a/Source/WebCore/dom/ScriptElement.h
+++ b/Source/WebCore/dom/ScriptElement.h
@@ -63,12 +63,14 @@ protected:
void setHaveFiredLoadEvent(bool haveFiredLoad) { m_haveFiredLoad = haveFiredLoad; }
bool isParserInserted() const { return m_parserInserted; }
bool alreadyStarted() const { return m_alreadyStarted; }
+ bool forceAsync() const { return m_forceAsync; }
// Helper functions used by our parent classes.
void insertedIntoDocument();
void removedFromDocument();
void childrenChanged();
void handleSourceAttribute(const String& sourceUrl);
+ void handleAsyncAttribute();
private:
bool ignoresLoadRequest() const;
@@ -98,6 +100,8 @@ private:
bool m_willBeParserExecuted : 1; // Same as "The parser will handle executing the script."
bool m_readyToBeParserExecuted : 1;
bool m_willExecuteWhenDocumentFinishedParsing : 1;
+ bool m_forceAsync : 1;
+ bool m_willExecuteInOrder : 1;
String m_characterEncoding;
String m_fallbackCharacterEncoding;
};
diff --git a/Source/WebCore/dom/ScriptExecutionContext.cpp b/Source/WebCore/dom/ScriptExecutionContext.cpp
index 6685416..b9a1e92 100644
--- a/Source/WebCore/dom/ScriptExecutionContext.cpp
+++ b/Source/WebCore/dom/ScriptExecutionContext.cpp
@@ -382,6 +382,8 @@ KURL ScriptExecutionContext::createPublicBlobURL(Blob* blob)
if (!blob)
return KURL();
KURL publicURL = BlobURL::createPublicURL(securityOrigin());
+ if (publicURL.isEmpty())
+ return KURL();
ThreadableBlobRegistry::registerBlobURL(publicURL, blob->url());
m_publicBlobURLs.add(publicURL.string());
return publicURL;
diff --git a/Source/WebCore/dom/ScriptExecutionContext.h b/Source/WebCore/dom/ScriptExecutionContext.h
index 3b37f0c..8407699 100644
--- a/Source/WebCore/dom/ScriptExecutionContext.h
+++ b/Source/WebCore/dom/ScriptExecutionContext.h
@@ -82,7 +82,7 @@ namespace WebCore {
void stopDatabases(DatabaseTaskSynchronizer*);
#endif
virtual bool isContextThread() const = 0;
- virtual bool isJSExecutionTerminated() const = 0;
+ virtual bool isJSExecutionForbidden() const = 0;
const KURL& url() const { return virtualURL(); }
KURL completeURL(const String& url) const { return virtualCompleteURL(url); }
diff --git a/Source/WebCore/dom/AsyncScriptRunner.cpp b/Source/WebCore/dom/ScriptRunner.cpp
index 28b1b31..10198bf 100644
--- a/Source/WebCore/dom/AsyncScriptRunner.cpp
+++ b/Source/WebCore/dom/ScriptRunner.cpp
@@ -24,7 +24,7 @@
*/
#include "config.h"
-#include "AsyncScriptRunner.h"
+#include "ScriptRunner.h"
#include "CachedScript.h"
#include "Document.h"
@@ -34,52 +34,79 @@
namespace WebCore {
-AsyncScriptRunner::AsyncScriptRunner(Document* document)
+ScriptRunner::ScriptRunner(Document* document)
: m_document(document)
- , m_timer(this, &AsyncScriptRunner::timerFired)
+ , m_timer(this, &ScriptRunner::timerFired)
{
ASSERT(document);
}
-AsyncScriptRunner::~AsyncScriptRunner()
+ScriptRunner::~ScriptRunner()
{
for (size_t i = 0; i < m_scriptsToExecuteSoon.size(); ++i)
m_document->decrementLoadEventDelayCount();
+ for (size_t i = 0; i < m_scriptsToExecuteInOrder.size(); ++i)
+ m_document->decrementLoadEventDelayCount();
}
-void AsyncScriptRunner::executeScriptSoon(ScriptElement* scriptElement, CachedResourceHandle<CachedScript> cachedScript)
+void ScriptRunner::queueScriptForExecution(ScriptElement* scriptElement, CachedResourceHandle<CachedScript> cachedScript, ExecutionType executionType)
{
- ASSERT_ARG(scriptElement, scriptElement);
+ ASSERT(scriptElement);
Element* element = scriptElement->element();
ASSERT(element);
ASSERT(element->inDocument());
m_document->incrementLoadEventDelayCount();
- m_scriptsToExecuteSoon.append(PendingScript(element, cachedScript.get()));
- if (!m_timer.isActive())
- m_timer.startOneShot(0);
+
+ switch (executionType) {
+ case ASYNC_EXECUTION:
+ m_scriptsToExecuteSoon.append(PendingScript(element, cachedScript.get()));
+ if (!m_timer.isActive())
+ m_timer.startOneShot(0);
+ break;
+
+ case IN_ORDER_EXECUTION:
+ m_scriptsToExecuteInOrder.append(PendingScript(element, cachedScript.get()));
+ break;
+
+ default:
+ ASSERT_NOT_REACHED();
+ }
}
-void AsyncScriptRunner::suspend()
+void ScriptRunner::suspend()
{
m_timer.stop();
}
-void AsyncScriptRunner::resume()
+void ScriptRunner::resume()
{
if (hasPendingScripts())
m_timer.startOneShot(0);
}
-void AsyncScriptRunner::timerFired(Timer<AsyncScriptRunner>* timer)
+void ScriptRunner::notifyInOrderScriptReady()
+{
+ ASSERT(!m_scriptsToExecuteInOrder.isEmpty());
+ m_timer.startOneShot(0);
+}
+
+void ScriptRunner::timerFired(Timer<ScriptRunner>* timer)
{
ASSERT_UNUSED(timer, timer == &m_timer);
RefPtr<Document> protect(m_document);
-
+
Vector<PendingScript> scripts;
scripts.swap(m_scriptsToExecuteSoon);
+
+ size_t numInOrderScriptsToExecute = 0;
+ for (; numInOrderScriptsToExecute < m_scriptsToExecuteInOrder.size() && m_scriptsToExecuteInOrder[numInOrderScriptsToExecute].cachedScript()->isLoaded(); ++numInOrderScriptsToExecute)
+ scripts.append(m_scriptsToExecuteInOrder[numInOrderScriptsToExecute]);
+ if (numInOrderScriptsToExecute)
+ m_scriptsToExecuteInOrder.remove(0, numInOrderScriptsToExecute);
+
size_t size = scripts.size();
for (size_t i = 0; i < size; ++i) {
CachedScript* cachedScript = scripts[i].cachedScript();
diff --git a/Source/WebCore/dom/AsyncScriptRunner.h b/Source/WebCore/dom/ScriptRunner.h
index 6a75323..d6d7411 100644
--- a/Source/WebCore/dom/AsyncScriptRunner.h
+++ b/Source/WebCore/dom/ScriptRunner.h
@@ -23,8 +23,8 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef AsyncScriptRunner_h
-#define AsyncScriptRunner_h
+#ifndef ScriptRunner_h
+#define ScriptRunner_h
#include "CachedResourceHandle.h"
#include "Timer.h"
@@ -38,26 +38,29 @@ class CachedScript;
class Document;
class PendingScript;
class ScriptElement;
-
-class AsyncScriptRunner {
- WTF_MAKE_NONCOPYABLE(AsyncScriptRunner); WTF_MAKE_FAST_ALLOCATED;
+
+class ScriptRunner {
+ WTF_MAKE_NONCOPYABLE(ScriptRunner); WTF_MAKE_FAST_ALLOCATED;
public:
- static PassOwnPtr<AsyncScriptRunner> create(Document* document) { return new AsyncScriptRunner(document); }
- ~AsyncScriptRunner();
+ static PassOwnPtr<ScriptRunner> create(Document* document) { return new ScriptRunner(document); }
+ ~ScriptRunner();
- void executeScriptSoon(ScriptElement*, CachedResourceHandle<CachedScript>);
- bool hasPendingScripts() const { return !m_scriptsToExecuteSoon.isEmpty(); }
+ enum ExecutionType { ASYNC_EXECUTION, IN_ORDER_EXECUTION };
+ void queueScriptForExecution(ScriptElement*, CachedResourceHandle<CachedScript>, ExecutionType);
+ bool hasPendingScripts() const { return !m_scriptsToExecuteSoon.isEmpty() || !m_scriptsToExecuteInOrder.isEmpty(); }
void suspend();
void resume();
+ void notifyInOrderScriptReady();
private:
- AsyncScriptRunner(Document*);
+ ScriptRunner(Document*);
- void timerFired(Timer<AsyncScriptRunner>*);
+ void timerFired(Timer<ScriptRunner>*);
Document* m_document;
+ Vector<PendingScript> m_scriptsToExecuteInOrder;
Vector<PendingScript> m_scriptsToExecuteSoon; // http://www.whatwg.org/specs/web-apps/current-work/#set-of-scripts-that-will-execute-as-soon-as-possible
- Timer<AsyncScriptRunner> m_timer;
+ Timer<ScriptRunner> m_timer;
};
}
diff --git a/Source/WebCore/dom/SelectElement.cpp b/Source/WebCore/dom/SelectElement.cpp
index 15c69ad..545f271 100644
--- a/Source/WebCore/dom/SelectElement.cpp
+++ b/Source/WebCore/dom/SelectElement.cpp
@@ -70,6 +70,74 @@ namespace WebCore {
static const DOMTimeStamp typeAheadTimeout = 1000;
+enum SkipDirection {
+ SkipBackwards = -1,
+ SkipForwards = 1
+};
+
+// Returns the 1st valid item |skip| items from |listIndex| in direction |direction| if there is one.
+// Otherwise, it returns the valid item closest to that boundary which is past |listIndex| if there is one.
+// Otherwise, it returns |listIndex|.
+// Valid means that it is enabled and an option element.
+static int nextValidIndex(const Vector<Element*>& listItems, int listIndex, SkipDirection direction, int skip)
+{
+ ASSERT(direction == -1 || direction == 1);
+ int lastGoodIndex = listIndex;
+ int size = listItems.size();
+ for (listIndex += direction; listIndex >= 0 && listIndex < size; listIndex += direction) {
+ --skip;
+ if (!listItems[listIndex]->disabled() && isOptionElement(listItems[listIndex])) {
+ lastGoodIndex = listIndex;
+ if (skip <= 0)
+ break;
+ }
+ }
+ return lastGoodIndex;
+}
+
+static int nextSelectableListIndex(SelectElementData& data, Element* element, int startIndex)
+{
+ return nextValidIndex(data.listItems(element), startIndex, SkipForwards, 1);
+}
+
+static int previousSelectableListIndex(SelectElementData& data, Element* element, int startIndex)
+{
+ if (startIndex == -1)
+ startIndex = data.listItems(element).size();
+ return nextValidIndex(data.listItems(element), startIndex, SkipBackwards, 1);
+}
+
+static int firstSelectableListIndex(SelectElementData& data, Element* element)
+{
+ const Vector<Element*>& items = data.listItems(element);
+ int index = nextValidIndex(items, items.size(), SkipBackwards, INT_MAX);
+ if (static_cast<unsigned>(index) == items.size())
+ return -1;
+ return index;
+}
+
+static int lastSelectableListIndex(SelectElementData& data, Element* element)
+{
+ return nextValidIndex(data.listItems(element), -1, SkipForwards, INT_MAX);
+}
+
+// Returns the index of the next valid item one page away from |startIndex| in direction |direction|.
+static int nextSelectableListIndexPageAway(SelectElementData& data, Element* element, int startIndex, SkipDirection direction)
+{
+ const Vector<Element*>& items = data.listItems(element);
+ // Can't use data->size() because renderer forces a minimum size.
+ int pageSize = 0;
+ if (element->renderer()->isListBox())
+ pageSize = toRenderListBox(element->renderer())->size() - 1; // -1 so we still show context
+
+ // One page away, but not outside valid bounds.
+ // If there is a valid option item one page away, the index is chosen.
+ // If there is no exact one page away valid option, returns startIndex or the most far index.
+ int edgeIndex = (direction == SkipForwards) ? 0 : (items.size() - 1);
+ int skipAmount = pageSize + ((direction == SkipForwards) ? startIndex : (edgeIndex - startIndex));
+ return nextValidIndex(items, edgeIndex, direction, skipAmount);
+}
+
void SelectElement::selectAll(SelectElementData& data, Element* element)
{
ASSERT(!data.usesMenuList());
@@ -104,30 +172,6 @@ void SelectElement::saveLastSelection(SelectElementData& data, Element* element)
}
}
-int SelectElement::nextSelectableListIndex(SelectElementData& data, Element* element, int startIndex)
-{
- const Vector<Element*>& items = data.listItems(element);
- int index = startIndex + 1;
- while (index >= 0 && (unsigned) index < items.size() && (!isOptionElement(items[index]) || items[index]->disabled()))
- ++index;
- if ((unsigned) index == items.size())
- return startIndex;
- return index;
-}
-
-int SelectElement::previousSelectableListIndex(SelectElementData& data, Element* element, int startIndex)
-{
- const Vector<Element*>& items = data.listItems(element);
- if (startIndex == -1)
- startIndex = items.size();
- int index = startIndex - 1;
- while (index >= 0 && (unsigned) index < items.size() && (!isOptionElement(items[index]) || items[index]->disabled()))
- --index;
- if (index == -1)
- return startIndex;
- return index;
-}
-
void SelectElement::setActiveSelectionAnchorIndex(SelectElementData& data, Element* element, int index)
{
data.setActiveSelectionAnchorIndex(index);
@@ -515,27 +559,6 @@ void SelectElement::reset(SelectElementData& data, Element* element)
setOptionsChangedOnRenderer(data, element);
element->setNeedsStyleRecalc();
}
-
-enum SkipDirection {
- SkipBackwards = -1,
- SkipForwards = 1
-};
-
-// Returns the index of the next valid list item |skip| items past |listIndex| in direction |direction|.
-static int nextValidIndex(const Vector<Element*>& listItems, int listIndex, SkipDirection direction, int skip)
-{
- int lastGoodIndex = listIndex;
- int size = listItems.size();
- for (listIndex += direction; listIndex >= 0 && listIndex < size; listIndex += direction) {
- --skip;
- if (!listItems[listIndex]->disabled() && isOptionElement(listItems[listIndex])) {
- lastGoodIndex = listIndex;
- if (skip <= 0)
- break;
- }
- }
- return lastGoodIndex;
-}
void SelectElement::menuListDefaultEventHandler(SelectElementData& data, Element* element, Event* event, HTMLFormElement* htmlForm)
{
@@ -594,8 +617,8 @@ void SelectElement::menuListDefaultEventHandler(SelectElementData& data, Element
listIndex = nextValidIndex(listItems, listItems.size(), SkipBackwards, 1);
handled = true;
}
-
- if (handled && listIndex >= 0 && (unsigned)listIndex < listItems.size())
+
+ if (handled && listIndex >= 0 && static_cast<unsigned>(listIndex) < listItems.size())
setSelectedIndex(data, element, listToOptionIndex(data, element, listIndex));
if (handled)
@@ -760,19 +783,47 @@ void SelectElement::listBoxDefaultEventHandler(SelectElementData& data, Element*
return;
const String& keyIdentifier = static_cast<KeyboardEvent*>(event)->keyIdentifier();
- int endIndex = 0;
+ bool handled = false;
+ int endIndex = 0;
if (data.activeSelectionEndIndex() < 0) {
// Initialize the end index
- if (keyIdentifier == "Down")
- endIndex = nextSelectableListIndex(data, element, lastSelectedListIndex(data, element));
- else if (keyIdentifier == "Up")
- endIndex = previousSelectableListIndex(data, element, optionToListIndex(data, element, selectedIndex(data, element)));
+ if (keyIdentifier == "Down" || keyIdentifier == "PageDown") {
+ int startIndex = lastSelectedListIndex(data, element);
+ handled = true;
+ if (keyIdentifier == "Down")
+ endIndex = nextSelectableListIndex(data, element, startIndex);
+ else
+ endIndex = nextSelectableListIndexPageAway(data, element, startIndex, SkipForwards);
+ } else if (keyIdentifier == "Up" || keyIdentifier == "PageUp") {
+ int startIndex = optionToListIndex(data, element, selectedIndex(data, element));
+ handled = true;
+ if (keyIdentifier == "Up")
+ endIndex = previousSelectableListIndex(data, element, startIndex);
+ else
+ endIndex = nextSelectableListIndexPageAway(data, element, startIndex, SkipBackwards);
+ }
} else {
// Set the end index based on the current end index
- if (keyIdentifier == "Down")
+ if (keyIdentifier == "Down") {
endIndex = nextSelectableListIndex(data, element, data.activeSelectionEndIndex());
- else if (keyIdentifier == "Up")
- endIndex = previousSelectableListIndex(data, element, data.activeSelectionEndIndex());
+ handled = true;
+ } else if (keyIdentifier == "Up") {
+ endIndex = previousSelectableListIndex(data, element, data.activeSelectionEndIndex());
+ handled = true;
+ } else if (keyIdentifier == "PageDown") {
+ endIndex = nextSelectableListIndexPageAway(data, element, data.activeSelectionEndIndex(), SkipForwards);
+ handled = true;
+ } else if (keyIdentifier == "PageUp") {
+ endIndex = nextSelectableListIndexPageAway(data, element, data.activeSelectionEndIndex(), SkipBackwards);
+ handled = true;
+ }
+ }
+ if (keyIdentifier == "Home") {
+ endIndex = firstSelectableListIndex(data, element);
+ handled = true;
+ } else if (keyIdentifier == "End") {
+ endIndex = lastSelectableListIndex(data, element);
+ handled = true;
}
if (isSpatialNavigationEnabled(element->document()->frame()))
@@ -780,13 +831,13 @@ void SelectElement::listBoxDefaultEventHandler(SelectElementData& data, Element*
if (keyIdentifier == "Left" || keyIdentifier == "Right" || ((keyIdentifier == "Down" || keyIdentifier == "Up") && endIndex == data.activeSelectionEndIndex()))
return;
- if (keyIdentifier == "Down" || keyIdentifier == "Up") {
+ if (endIndex >= 0 && handled) {
// Save the selection so it can be compared to the new selection when dispatching change events immediately after making the new selection.
saveLastSelection(data, element);
- ASSERT_UNUSED(listItems, !listItems.size() || (endIndex >= 0 && (unsigned) endIndex < listItems.size()));
+ ASSERT_UNUSED(listItems, !listItems.size() || (endIndex >= 0 && static_cast<unsigned>(endIndex) < listItems.size()));
setActiveSelectionEndIndex(data, endIndex);
-
+
bool selectNewItem = !data.multiple() || static_cast<KeyboardEvent*>(event)->shiftKey() || !isSpatialNavigationEnabled(element->document()->frame());
if (selectNewItem)
data.setActiveSelectionState(true);
diff --git a/Source/WebCore/dom/SelectElement.h b/Source/WebCore/dom/SelectElement.h
index 222a1bb..dd073a2 100644
--- a/Source/WebCore/dom/SelectElement.h
+++ b/Source/WebCore/dom/SelectElement.h
@@ -72,8 +72,6 @@ protected:
static void selectAll(SelectElementData&, Element*);
static void saveLastSelection(SelectElementData&, Element*);
- static int nextSelectableListIndex(SelectElementData&, Element*, int startIndex);
- static int previousSelectableListIndex(SelectElementData&, Element*, int startIndex);
static void setActiveSelectionAnchorIndex(SelectElementData&, Element*, int index);
static void setActiveSelectionEndIndex(SelectElementData&, int index);
static void updateListBoxSelection(SelectElementData&, Element*, bool deselectOtherOptions);
diff --git a/Source/WebCore/dom/ShadowRoot.cpp b/Source/WebCore/dom/ShadowRoot.cpp
new file mode 100644
index 0000000..8fe56b5
--- /dev/null
+++ b/Source/WebCore/dom/ShadowRoot.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ShadowRoot.h"
+
+namespace WebCore {
+
+ShadowRoot::ShadowRoot(Document* document)
+ : DocumentFragment(document)
+{
+ ASSERT(document);
+}
+
+String ShadowRoot::nodeName() const
+{
+ return "#shadow-root";
+}
+
+void ShadowRoot::recalcStyle(StyleChange change)
+{
+ for (Node* n = firstChild(); n; n = n->nextSibling())
+ n->recalcStyle(change);
+
+ clearNeedsStyleRecalc();
+ clearChildNeedsStyleRecalc();
+}
+
+}
diff --git a/Source/WebCore/dom/ShadowRoot.h b/Source/WebCore/dom/ShadowRoot.h
new file mode 100644
index 0000000..aeccd8a
--- /dev/null
+++ b/Source/WebCore/dom/ShadowRoot.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ShadowRoot_h
+#define ShadowRoot_h
+
+#include "DocumentFragment.h"
+
+namespace WebCore {
+
+class Document;
+
+class ShadowRoot : public DocumentFragment {
+public:
+ static PassRefPtr<ShadowRoot> create(Document*);
+
+ virtual bool isShadowBoundary() const { return true; }
+ virtual void recalcStyle(StyleChange = NoChange);
+
+private:
+ ShadowRoot(Document*);
+ virtual String nodeName() const;
+};
+
+inline PassRefPtr<ShadowRoot> ShadowRoot::create(Document* document)
+{
+ return adoptRef(new ShadowRoot(document));
+}
+
+} // namespace
+
+#endif
diff --git a/Source/WebCore/dom/StringCallback.cpp b/Source/WebCore/dom/StringCallback.cpp
new file mode 100644
index 0000000..c6285b1
--- /dev/null
+++ b/Source/WebCore/dom/StringCallback.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "StringCallback.h"
+
+#include "ScriptExecutionContext.h"
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+namespace {
+
+class DispatchCallbackTask : public ScriptExecutionContext::Task {
+public:
+ static PassOwnPtr<DispatchCallbackTask> create(PassRefPtr<StringCallback> callback, const String& data)
+ {
+ return adoptPtr(new DispatchCallbackTask(callback, data));
+ }
+
+ virtual void performTask(ScriptExecutionContext*)
+ {
+ m_callback->handleEvent(m_data);
+ }
+
+private:
+ DispatchCallbackTask(PassRefPtr<StringCallback> callback, const String& data)
+ : m_callback(callback)
+ , m_data(data)
+ {
+ }
+
+ RefPtr<StringCallback> m_callback;
+ const String m_data;
+};
+
+} // namespace
+
+void StringCallback::scheduleCallback(ScriptExecutionContext* context, const String& data)
+{
+ context->postTask(DispatchCallbackTask::create(this, data));
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/dom/StringCallback.h b/Source/WebCore/dom/StringCallback.h
new file mode 100644
index 0000000..92e83e2
--- /dev/null
+++ b/Source/WebCore/dom/StringCallback.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef StringCallback_h
+#define StringCallback_h
+
+#include <wtf/Forward.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class ScriptExecutionContext;
+
+class StringCallback : public RefCounted<StringCallback> {
+public:
+ virtual ~StringCallback() { }
+ virtual bool handleEvent(const String& data) = 0;
+
+ // Helper to post callback task.
+ void scheduleCallback(ScriptExecutionContext*, const String& data);
+};
+
+} // namespace WebCore
+
+#endif // StringCallback_h
diff --git a/Source/WebCore/dom/StringCallback.idl b/Source/WebCore/dom/StringCallback.idl
new file mode 100644
index 0000000..1e18d83
--- /dev/null
+++ b/Source/WebCore/dom/StringCallback.idl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module core {
+ interface [
+ Callback
+ ] StringCallback {
+ boolean handleEvent(in DOMString data);
+ };
+}
diff --git a/Source/WebCore/dom/StyleElement.cpp b/Source/WebCore/dom/StyleElement.cpp
index f984fda..9892ed7 100644
--- a/Source/WebCore/dom/StyleElement.cpp
+++ b/Source/WebCore/dom/StyleElement.cpp
@@ -103,8 +103,10 @@ void StyleElement::process(Element* e)
for (Node* c = e->firstChild(); c; c = c->nextSibling()) {
if (isValidStyleChild(c)) {
unsigned length = c->nodeValue().length();
- if (length > std::numeric_limits<unsigned>::max() - resultLength)
- CRASH();
+ if (length > std::numeric_limits<unsigned>::max() - resultLength) {
+ createSheet(e, m_startLineNumber, "");
+ return;
+ }
resultLength += length;
}
}
diff --git a/Source/WebCore/dom/StyledElement.cpp b/Source/WebCore/dom/StyledElement.cpp
index d6a532f..6781ed5 100644
--- a/Source/WebCore/dom/StyledElement.cpp
+++ b/Source/WebCore/dom/StyledElement.cpp
@@ -233,18 +233,9 @@ void StyledElement::classAttributeChanged(const AtomicString& newClassString)
void StyledElement::parseMappedAttribute(Attribute* attr)
{
- if (isIdAttributeName(attr->name())) {
- setHasID(!attr->isNull());
- if (attributeMap()) {
- if (attr->isNull())
- attributeMap()->setIdForStyleResolution(nullAtom);
- else if (document()->inQuirksMode())
- attributeMap()->setIdForStyleResolution(attr->value().lower());
- else
- attributeMap()->setIdForStyleResolution(attr->value());
- }
- setNeedsStyleRecalc();
- } else if (attr->name() == classAttr)
+ if (isIdAttributeName(attr->name()))
+ idAttributeChanged(attr);
+ else if (attr->name() == classAttr)
classAttributeChanged(attr->value());
else if (attr->name() == styleAttr) {
if (attr->isNull())
@@ -412,7 +403,7 @@ unsigned MappedAttributeHash::hash(const MappedAttributeKey& key)
COMPILE_ASSERT(sizeof(key.name) == 4 || sizeof(key.name) == 8, key_name_size);
COMPILE_ASSERT(sizeof(key.value) == 4 || sizeof(key.value) == 8, key_value_size);
- WTF::StringHasher hasher;
+ StringHasher hasher;
const UChar* data;
data = reinterpret_cast<const UChar*>(&key.name);
diff --git a/Source/WebCore/dom/Text.cpp b/Source/WebCore/dom/Text.cpp
index 5a28e37..906e421 100644
--- a/Source/WebCore/dom/Text.cpp
+++ b/Source/WebCore/dom/Text.cpp
@@ -292,7 +292,7 @@ void Text::recalcStyle(StyleChange change)
clearNeedsStyleRecalc();
}
-bool Text::childTypeAllowed(NodeType)
+bool Text::childTypeAllowed(NodeType) const
{
return false;
}
diff --git a/Source/WebCore/dom/Text.h b/Source/WebCore/dom/Text.h
index f693f3b..5995f1f 100644
--- a/Source/WebCore/dom/Text.h
+++ b/Source/WebCore/dom/Text.h
@@ -56,7 +56,7 @@ private:
virtual bool rendererIsNeeded(RenderStyle*);
virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
virtual void recalcStyle(StyleChange = NoChange);
- virtual bool childTypeAllowed(NodeType);
+ virtual bool childTypeAllowed(NodeType) const;
virtual PassRefPtr<Text> virtualCreate(const String&);
diff --git a/Source/WebCore/dom/TreeScope.cpp b/Source/WebCore/dom/TreeScope.cpp
new file mode 100644
index 0000000..a995a2d
--- /dev/null
+++ b/Source/WebCore/dom/TreeScope.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2011 Google Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 "TreeScope.h"
+
+#include "Element.h"
+#include "HTMLAnchorElement.h"
+#include "HTMLMapElement.h"
+#include "HTMLNames.h"
+#include "NodeRareData.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+TreeScope::TreeScope(Document* document, ConstructionType constructionType)
+ : ContainerNode(0, constructionType)
+ , m_parentTreeScope(0)
+ , m_accessKeyMapValid(false)
+ , m_numNodeListCaches(0)
+{
+ m_document = document;
+ if (document != this) {
+ // Assume document as parent scope
+ m_parentTreeScope = document;
+ // FIXME: This branch should be inert until shadow scopes are landed.
+ ASSERT_NOT_REACHED();
+ }
+}
+
+TreeScope::~TreeScope()
+{
+ if (hasRareData())
+ rareData()->setTreeScope(0);
+}
+
+void TreeScope::destroyTreeScopeData()
+{
+ m_elementsById.clear();
+ m_imageMapsByName.clear();
+ m_elementsByAccessKey.clear();
+}
+
+void TreeScope::setParentTreeScope(TreeScope* newParentScope)
+{
+ // A document node cannot be re-parented.
+ ASSERT(!isDocumentNode());
+ // Every scope other than document needs a parent scope.
+ ASSERT(m_parentTreeScope);
+ ASSERT(newParentScope);
+
+ m_parentTreeScope = newParentScope;
+}
+
+Element* TreeScope::getElementById(const AtomicString& elementId) const
+{
+ if (elementId.isEmpty())
+ return 0;
+ return m_elementsById.getElementById(elementId.impl(), this);
+}
+
+void TreeScope::addElementById(const AtomicString& elementId, Element* element)
+{
+ m_elementsById.add(elementId.impl(), element);
+}
+
+void TreeScope::removeElementById(const AtomicString& elementId, Element* element)
+{
+ m_elementsById.remove(elementId.impl(), element);
+}
+
+Element* TreeScope::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 TreeScope::invalidateAccessKeyMap()
+{
+ m_accessKeyMapValid = false;
+ m_elementsByAccessKey.clear();
+}
+
+void TreeScope::addImageMap(HTMLMapElement* imageMap)
+{
+ AtomicStringImpl* name = imageMap->getName().impl();
+ if (!name)
+ return;
+ m_imageMapsByName.add(name, imageMap);
+}
+
+void TreeScope::removeImageMap(HTMLMapElement* imageMap)
+{
+ AtomicStringImpl* name = imageMap->getName().impl();
+ if (!name)
+ return;
+ m_imageMapsByName.remove(name, imageMap);
+}
+
+HTMLMapElement* TreeScope::getImageMap(const String& url) const
+{
+ if (url.isNull())
+ return 0;
+ size_t hashPos = url.find('#');
+ String name = (hashPos == notFound ? url : url.substring(hashPos + 1)).impl();
+ if (document()->isHTMLDocument())
+ return static_cast<HTMLMapElement*>(m_imageMapsByName.getElementByLowercasedMapName(AtomicString(name.lower()).impl(), this));
+ return static_cast<HTMLMapElement*>(m_imageMapsByName.getElementByMapName(AtomicString(name).impl(), this));
+}
+
+Element* TreeScope::findAnchor(const String& name)
+{
+ if (name.isEmpty())
+ return 0;
+ if (Element* element = getElementById(name))
+ return element;
+ for (Node* node = this; node; node = node->traverseNextNode()) {
+ if (node->hasTagName(aTag)) {
+ HTMLAnchorElement* anchor = static_cast<HTMLAnchorElement*>(node);
+ if (document()->inQuirksMode()) {
+ // Quirks mode, case insensitive comparison of names.
+ if (equalIgnoringCase(anchor->name(), name))
+ return anchor;
+ } else {
+ // Strict mode, names need to match exactly.
+ if (anchor->name() == name)
+ return anchor;
+ }
+ }
+ }
+ return 0;
+}
+
+} // namespace WebCore
+
diff --git a/Source/WebCore/dom/TreeScope.h b/Source/WebCore/dom/TreeScope.h
new file mode 100644
index 0000000..6271541
--- /dev/null
+++ b/Source/WebCore/dom/TreeScope.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2011 Google Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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 TreeScope_h
+#define TreeScope_h
+
+#include "ContainerNode.h"
+#include "DocumentOrderedMap.h"
+
+namespace WebCore {
+
+class Element;
+class HTMLMapElement;
+
+class TreeScope : public ContainerNode {
+ friend class Document;
+
+public:
+ TreeScope* parentTreeScope() const { return m_parentTreeScope; }
+
+ Element* getElementById(const AtomicString&) const;
+ bool hasElementWithId(AtomicStringImpl* id) const;
+ bool containsMultipleElementsWithId(const AtomicString& id) const;
+ void addElementById(const AtomicString& elementId, Element*);
+ void removeElementById(const AtomicString& elementId, Element*);
+
+ void addImageMap(HTMLMapElement*);
+ void removeImageMap(HTMLMapElement*);
+ HTMLMapElement* getImageMap(const String& url) const;
+
+ Element* getElementByAccessKey(const String& key) const;
+ void invalidateAccessKeyMap();
+
+ void addNodeListCache() { ++m_numNodeListCaches; }
+ void removeNodeListCache() { ASSERT(m_numNodeListCaches > 0); --m_numNodeListCaches; }
+ bool hasNodeListCaches() const { return m_numNodeListCaches; }
+
+ // Find first anchor with the given name.
+ // First searches for an element with the given ID, but if that fails, then looks
+ // for an anchor with the given name. ID matching is always case sensitive, but
+ // Anchor name matching is case sensitive in strict mode and not case sensitive in
+ // quirks mode for historical compatibility reasons.
+ Element* findAnchor(const String& name);
+
+protected:
+ TreeScope(Document*, ConstructionType = CreateContainer);
+
+ virtual ~TreeScope();
+
+ void destroyTreeScopeData();
+
+ void setParentTreeScope(TreeScope*);
+
+private:
+ TreeScope* m_parentTreeScope;
+
+ DocumentOrderedMap m_elementsById;
+ DocumentOrderedMap m_imageMapsByName;
+
+ mutable HashMap<StringImpl*, Element*, CaseFoldingHash> m_elementsByAccessKey;
+ mutable bool m_accessKeyMapValid;
+
+ unsigned m_numNodeListCaches;
+};
+
+inline bool TreeScope::hasElementWithId(AtomicStringImpl* id) const
+{
+ ASSERT(id);
+ return m_elementsById.contains(id);
+}
+
+inline bool TreeScope::containsMultipleElementsWithId(const AtomicString& id) const
+{
+ return m_elementsById.containsMultiple(id.impl());
+}
+
+} // namespace WebCore
+
+#endif // TreeScope_h
+
diff --git a/Source/WebCore/dom/UIEvent.cpp b/Source/WebCore/dom/UIEvent.cpp
index 401015b..dfdd34d 100644
--- a/Source/WebCore/dom/UIEvent.cpp
+++ b/Source/WebCore/dom/UIEvent.cpp
@@ -69,12 +69,12 @@ int UIEvent::charCode() const
return 0;
}
-int UIEvent::layerX() const
+int UIEvent::layerX()
{
return 0;
}
-int UIEvent::layerY() const
+int UIEvent::layerY()
{
return 0;
}
diff --git a/Source/WebCore/dom/UIEvent.h b/Source/WebCore/dom/UIEvent.h
index 8e330a5..a2f4e65 100644
--- a/Source/WebCore/dom/UIEvent.h
+++ b/Source/WebCore/dom/UIEvent.h
@@ -53,8 +53,8 @@ namespace WebCore {
virtual int keyCode() const;
virtual int charCode() const;
- virtual int layerX() const;
- virtual int layerY() const;
+ virtual int layerX();
+ virtual int layerY();
virtual int pageX() const;
virtual int pageY() const;
diff --git a/Source/WebCore/dom/ViewportArguments.cpp b/Source/WebCore/dom/ViewportArguments.cpp
index e75a3eb..49c94d7 100644
--- a/Source/WebCore/dom/ViewportArguments.cpp
+++ b/Source/WebCore/dom/ViewportArguments.cpp
@@ -257,32 +257,32 @@ static float findScaleValue(const String& keyString, const String& valueString,
return value;
}
-static bool findUserScalableValue(const String& keyString, const String& valueString, Document* document)
+static float findUserScalableValue(const String& keyString, const String& valueString, Document* document)
{
// yes and no are used as keywords.
// Numbers >= 1, numbers <= -1, device-width and device-height are mapped to yes.
// Numbers in the range <-1, 1>, and unknown values, are mapped to no.
if (equalIgnoringCase(valueString, "yes"))
- return true;
+ return 1;
if (equalIgnoringCase(valueString, "no"))
- return false;
+ return 0;
if (equalIgnoringCase(valueString, "desktop-width"))
- return true;
+ return 1;
if (equalIgnoringCase(valueString, "device-width"))
- return true;
+ return 1;
if (equalIgnoringCase(valueString, "device-height"))
- return true;
+ return 1;
bool ok;
float value = numericPrefix(keyString, valueString, document, &ok);
if (!ok)
- return false;
+ return 0;
if (fabs(value) < 1)
- return false;
+ return 0;
- return true;
+ return 1;
}
static float findTargetDensityDPIValue(const String& keyString, const String& valueString, Document* document)
diff --git a/Source/WebCore/dom/ViewportArguments.h b/Source/WebCore/dom/ViewportArguments.h
index 2e0fd19..66bb281 100644
--- a/Source/WebCore/dom/ViewportArguments.h
+++ b/Source/WebCore/dom/ViewportArguments.h
@@ -51,7 +51,7 @@ struct ViewportAttributes {
float minimumScale;
float maximumScale;
- bool userScalable;
+ float userScalable;
};
struct ViewportArguments {
@@ -74,7 +74,7 @@ struct ViewportArguments {
, width(ValueAuto)
, height(ValueAuto)
, targetDensityDpi(ValueAuto)
- , userScalable(true)
+ , userScalable(ValueAuto)
{
}
@@ -84,8 +84,7 @@ struct ViewportArguments {
float width;
float height;
float targetDensityDpi;
-
- bool userScalable;
+ float userScalable;
bool operator==(const ViewportArguments& other) const
{
diff --git a/Source/WebCore/dom/WheelEvent.cpp b/Source/WebCore/dom/WheelEvent.cpp
index 0981a57..a673c93 100644
--- a/Source/WebCore/dom/WheelEvent.cpp
+++ b/Source/WebCore/dom/WheelEvent.cpp
@@ -23,7 +23,10 @@
#include "config.h"
#include "WheelEvent.h"
+#include "EventDispatcher.h"
#include "EventNames.h"
+#include "PlatformWheelEvent.h"
+
#include <wtf/MathExtras.h>
namespace WebCore {
@@ -92,4 +95,32 @@ bool WheelEvent::isWheelEvent() const
return true;
}
+inline static WheelEvent::Granularity granularity(const PlatformWheelEvent& event)
+{
+ return event.granularity() == ScrollByPageWheelEvent ? WheelEvent::Page : WheelEvent::Pixel;
+}
+
+WheelEventDispatchMediator::WheelEventDispatchMediator(const PlatformWheelEvent& event, PassRefPtr<AbstractView> view)
+{
+ if (!(event.deltaX() || event.deltaY()))
+ return;
+
+ setEvent(WheelEvent::create(event.wheelTicksX(), event.wheelTicksY(), event.deltaX(), event.deltaY(), granularity(event),
+ view, event.globalX(), event.globalY(), event.x(), event.y(), event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey()));
+
+}
+
+WheelEvent* WheelEventDispatchMediator::event() const
+{
+ return static_cast<WheelEvent*>(EventDispatchMediator::event());
+}
+
+bool WheelEventDispatchMediator::dispatchEvent(EventDispatcher* dispatcher) const
+{
+ if (!event())
+ return true;
+
+ return EventDispatchMediator::dispatchEvent(dispatcher) && !event()->defaultHandled();
+}
+
} // namespace WebCore
diff --git a/Source/WebCore/dom/WheelEvent.h b/Source/WebCore/dom/WheelEvent.h
index b085e86..5f0d569 100644
--- a/Source/WebCore/dom/WheelEvent.h
+++ b/Source/WebCore/dom/WheelEvent.h
@@ -82,6 +82,15 @@ namespace WebCore {
Granularity m_granularity;
};
+class WheelEventDispatchMediator : public EventDispatchMediator {
+public:
+ WheelEventDispatchMediator(const PlatformWheelEvent&, PassRefPtr<AbstractView>);
+
+private:
+ WheelEvent* event() const;
+ virtual bool dispatchEvent(EventDispatcher*) const;
+};
+
} // namespace WebCore
#endif // WheelEvent_h
diff --git a/Source/WebCore/dom/XMLDocumentParser.cpp b/Source/WebCore/dom/XMLDocumentParser.cpp
index a5d3c08..67d90d9 100644
--- a/Source/WebCore/dom/XMLDocumentParser.cpp
+++ b/Source/WebCore/dom/XMLDocumentParser.cpp
@@ -294,7 +294,7 @@ void XMLDocumentParser::insertErrorMessageBlock()
// Create elements for display
ExceptionCode ec = 0;
Document* document = this->document();
- Element* documentElement = document->documentElement();
+ RefPtr<Element> documentElement = document->documentElement();
if (!documentElement) {
RefPtr<Element> rootElement = document->createElement(htmlTag, false);
document->appendChild(rootElement, ec);
diff --git a/Source/WebCore/dom/XMLDocumentParserLibxml2.cpp b/Source/WebCore/dom/XMLDocumentParserLibxml2.cpp
index 9214391..d806456 100644
--- a/Source/WebCore/dom/XMLDocumentParserLibxml2.cpp
+++ b/Source/WebCore/dom/XMLDocumentParserLibxml2.cpp
@@ -847,12 +847,16 @@ void XMLDocumentParser::endElementNs()
return;
}
+ // JavaScript can detach the parser. Make sure this is not released
+ // before the end of this method.
+ RefPtr<XMLDocumentParser> protect(this);
+
exitText();
- Node* n = m_currentNode;
+ RefPtr<Node> n = m_currentNode;
n->finishParsingChildren();
- if (m_scriptingPermission == FragmentScriptingNotAllowed && n->isElementNode() && toScriptElement(static_cast<Element*>(n))) {
+ if (m_scriptingPermission == FragmentScriptingNotAllowed && n->isElementNode() && toScriptElement(static_cast<Element*>(n.get()))) {
popCurrentNode();
ExceptionCode ec;
n->remove(ec);
@@ -864,7 +868,7 @@ void XMLDocumentParser::endElementNs()
return;
}
- Element* element = static_cast<Element*>(n);
+ Element* element = static_cast<Element*>(n.get());
// The element's parent may have already been removed from document.
// Parsing continues in this case, but scripts aren't executed.
@@ -893,10 +897,6 @@ void XMLDocumentParser::endElementNs()
// FIXME: Script execution should be shared between
// the libxml2 and Qt XMLDocumentParser implementations.
- // JavaScript can detach the parser. Make sure this is not released
- // before the end of this method.
- RefPtr<XMLDocumentParser> protect(this);
-
if (scriptElement->readyToBeParserExecuted())
scriptElement->executeScript(ScriptSourceCode(scriptElement->scriptContent(), document()->url(), m_scriptStartPosition));
else if (scriptElement->willBeParserExecuted()) {
@@ -1341,25 +1341,21 @@ void XMLDocumentParser::doEnd()
#if ENABLE(XSLT)
XMLTreeViewer xmlTreeViewer(document());
-
bool xmlViewerMode = !m_sawError && !m_sawCSS && !m_sawXSLTransform && xmlTreeViewer.hasNoStyleInformation();
+ if (xmlViewerMode)
+ xmlTreeViewer.transformDocumentToTreeView();
- if (xmlViewerMode || m_sawXSLTransform) {
+ if (m_sawXSLTransform) {
void* doc = xmlDocPtrForString(document()->cachedResourceLoader(), m_originalSourceForTransform, document()->url().string());
document()->setTransformSource(new TransformSource(doc));
- if (xmlViewerMode)
- xmlTreeViewer.transformDocumentToTreeView();
- else {
- document()->setParsing(false); // Make the document think it's done, so it will apply XSL stylesheets.
- document()->styleSelectorChanged(RecalcStyleImmediately);
- document()->setParsing(true);
- }
+ document()->setParsing(false); // Make the document think it's done, so it will apply XSL stylesheets.
+ document()->styleSelectorChanged(RecalcStyleImmediately);
+ document()->setParsing(true);
DocumentParser::stopParsing();
}
#endif
-
}
#if ENABLE(XSLT)
diff --git a/Source/WebCore/dom/XMLDocumentParserQt.cpp b/Source/WebCore/dom/XMLDocumentParserQt.cpp
index 6219bcd..dd9d504 100644
--- a/Source/WebCore/dom/XMLDocumentParserQt.cpp
+++ b/Source/WebCore/dom/XMLDocumentParserQt.cpp
@@ -556,10 +556,10 @@ void XMLDocumentParser::parseEndElement()
{
exitText();
- Node* n = m_currentNode;
+ RefPtr<Node> n = m_currentNode;
n->finishParsingChildren();
- if (m_scriptingPermission == FragmentScriptingNotAllowed && n->isElementNode() && toScriptElement(static_cast<Element*>(n))) {
+ if (m_scriptingPermission == FragmentScriptingNotAllowed && n->isElementNode() && toScriptElement(static_cast<Element*>(n.get()))) {
popCurrentNode();
ExceptionCode ec;
n->remove(ec);
@@ -572,7 +572,7 @@ void XMLDocumentParser::parseEndElement()
return;
}
- Element* element = static_cast<Element*>(n);
+ Element* element = static_cast<Element*>(n.get());
// The element's parent may have already been removed from document.
// Parsing continues in this case, but scripts aren't executed.
diff --git a/Source/WebCore/dom/default/PlatformMessagePortChannel.h b/Source/WebCore/dom/default/PlatformMessagePortChannel.h
index 2aad952..651810b 100644
--- a/Source/WebCore/dom/default/PlatformMessagePortChannel.h
+++ b/Source/WebCore/dom/default/PlatformMessagePortChannel.h
@@ -44,7 +44,7 @@ namespace WebCore {
// PlatformMessagePortChannel is a platform-dependent interface to the remote side of a message channel.
// This default implementation supports multiple threads running within a single process. Implementations for multi-process platforms should define these public APIs in their own platform-specific PlatformMessagePortChannel file.
// The goal of this implementation is to eliminate contention except when cloning or closing the port, so each side of the channel has its own separate mutex.
- class PlatformMessagePortChannel : public ThreadSafeShared<PlatformMessagePortChannel> {
+ class PlatformMessagePortChannel : public ThreadSafeRefCounted<PlatformMessagePortChannel> {
public:
static void createChannel(PassRefPtr<MessagePort>, PassRefPtr<MessagePort>);
@@ -59,7 +59,7 @@ namespace WebCore {
MessagePort* locallyEntangledPort(const ScriptExecutionContext*);
// Wrapper for MessageQueue that allows us to do thread safe sharing by two proxies.
- class MessagePortQueue : public ThreadSafeShared<MessagePortQueue> {
+ class MessagePortQueue : public ThreadSafeRefCounted<MessagePortQueue> {
public:
static PassRefPtr<MessagePortQueue> create() { return adoptRef(new MessagePortQueue()); }
diff --git a/Source/WebCore/dom/make_names.pl b/Source/WebCore/dom/make_names.pl
index 836137e..674831c 100755
--- a/Source/WebCore/dom/make_names.pl
+++ b/Source/WebCore/dom/make_names.pl
@@ -3,6 +3,7 @@
# Copyright (C) 2005, 2006, 2007, 2009 Apple Inc. All rights reserved.
# Copyright (C) 2009, Julien Chaffraix <jchaffraix@webkit.org>
# Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
+# Copyright (C) 2011 Ericsson AB. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -65,7 +66,7 @@ if ($ENV{CC}) {
} else {
$gccLocation = "/usr/bin/gcc";
}
-my $preprocessor = $gccLocation . " -E -P -x c++";
+my $preprocessor = $gccLocation . " -E -x c++";
GetOptions(
'tags=s' => \$tagsFile,
@@ -596,6 +597,10 @@ sub printJSElementIncludes
for my $tagName (sort keys %enabledTags) {
my $JSInterfaceName = $enabledTags{$tagName}{JSInterfaceName};
next if defined($tagsSeen{$JSInterfaceName}) || usesDefaultJSWrapper($tagName);
+ if ($enabledTags{$tagName}{conditional}) {
+ # We skip feature-define-specific #includes here since we handle them separately.
+ next;
+ }
$tagsSeen{$JSInterfaceName} = 1;
print F "#include \"${wrapperFactoryType}${JSInterfaceName}.h\"\n";
@@ -610,12 +615,54 @@ sub printElementIncludes
for my $tagName (sort keys %enabledTags) {
my $interfaceName = $enabledTags{$tagName}{interfaceName};
next if defined($tagsSeen{$interfaceName});
+ if ($enabledTags{$tagName}{conditional}) {
+ # We skip feature-define-specific #includes here since we handle them separately.
+ next;
+ }
$tagsSeen{$interfaceName} = 1;
print F "#include \"${interfaceName}.h\"\n";
}
}
+sub printConditionalElementIncludes
+{
+ my ($F, $wrapperFactoryType) = @_;
+
+ my %conditionals;
+ my %unconditionalElementIncludes;
+ my %unconditionalJSElementIncludes;
+
+ for my $tagName (keys %enabledTags) {
+ my $conditional = $enabledTags{$tagName}{conditional};
+ my $interfaceName = $enabledTags{$tagName}{interfaceName};
+ my $JSInterfaceName = $enabledTags{$tagName}{JSInterfaceName};
+
+ if ($conditional) {
+ $conditionals{$conditional}{interfaceNames}{$interfaceName} = 1;
+ $conditionals{$conditional}{JSInterfaceNames}{$JSInterfaceName} = 1;
+ } else {
+ $unconditionalElementIncludes{$interfaceName} = 1;
+ $unconditionalJSElementIncludes{$JSInterfaceName} = 1;
+ }
+ }
+
+ for my $conditional (sort keys %conditionals) {
+ print F "\n#if ENABLE($conditional)\n";
+ for my $interfaceName (sort keys %{$conditionals{$conditional}{interfaceNames}}) {
+ next if $unconditionalElementIncludes{$interfaceName};
+ print F "#include \"$interfaceName.h\"\n";
+ }
+ if ($wrapperFactoryType) {
+ for my $JSInterfaceName (sort keys %{$conditionals{$conditional}{JSInterfaceNames}}) {
+ next if $unconditionalJSElementIncludes{$JSInterfaceName};
+ print F "#include \"$wrapperFactoryType$JSInterfaceName.h\"\n";
+ }
+ }
+ print F "#endif\n";
+ }
+}
+
sub printDefinitions
{
my ($F, $namesRef, $type, $namespaceURI) = @_;
@@ -661,8 +708,11 @@ END
printElementIncludes($F);
+print F "\n#include <wtf/HashMap.h>\n";
+
+printConditionalElementIncludes($F);
+
print F <<END
-#include <wtf/HashMap.h>
#if ENABLE(DASHBOARD_SUPPORT) || ENABLE(VIDEO)
#include "Document.h"
@@ -922,8 +972,11 @@ sub printWrapperFactoryCppFile
printElementIncludes($F);
+ print F "\n#include <wtf/StdLibExtras.h>\n";
+
+ printConditionalElementIncludes($F, $wrapperFactoryType);
+
print F <<END
-#include <wtf/StdLibExtras.h>
#if ENABLE(VIDEO)
#include "Document.h"