diff options
Diffstat (limited to 'Source/WebCore/dom')
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" |