diff options
Diffstat (limited to 'Source/WebCore/dom')
27 files changed, 611 insertions, 229 deletions
diff --git a/Source/WebCore/dom/Attr.cpp b/Source/WebCore/dom/Attr.cpp index e3ae348..346a819 100644 --- a/Source/WebCore/dom/Attr.cpp +++ b/Source/WebCore/dom/Attr.cpp @@ -69,6 +69,8 @@ void Attr::createTextChild() textNode->setParent(this); setFirstChild(textNode.get()); setLastChild(textNode.get()); + textNode->updateNextNode(); + textNode->updatePreviousNode(); } } diff --git a/Source/WebCore/dom/CharacterData.cpp b/Source/WebCore/dom/CharacterData.cpp index b4af02d..78f57d0 100644 --- a/Source/WebCore/dom/CharacterData.cpp +++ b/Source/WebCore/dom/CharacterData.cpp @@ -189,6 +189,7 @@ void CharacterData::updateRenderer(unsigned offsetOfReplacedData, unsigned lengt void CharacterData::dispatchModifiedEvent(StringImpl* oldData) { + updatePrevNextNodesInSubtree(); if (parentNode()) parentNode()->childrenChanged(); if (document()->hasListenerType(Document::DOMCHARACTERDATAMODIFIED_LISTENER)) diff --git a/Source/WebCore/dom/ContainerNode.cpp b/Source/WebCore/dom/ContainerNode.cpp index 2d22fa9..5574aa5 100644 --- a/Source/WebCore/dom/ContainerNode.cpp +++ b/Source/WebCore/dom/ContainerNode.cpp @@ -3,6 +3,7 @@ * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2001 Dirk Mueller (mueller@kde.org) * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2012 The Linux Foundation 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 @@ -74,6 +75,7 @@ static void collectTargetNodes(Node* node, NodeVector& nodes) void ContainerNode::removeAllChildren() { removeAllChildrenInContainer<Node, ContainerNode>(this); + updateNextNode(); } void ContainerNode::takeAllChildrenFrom(ContainerNode* oldParent) @@ -208,6 +210,8 @@ void ContainerNode::insertBeforeCommon(Node* nextChild, Node* newChild) newChild->setParent(this); newChild->setPreviousSibling(prev); newChild->setNextSibling(nextChild); + newChild->updatePreviousNode(); + newChild->lastDescendantNode(true)->updateNextNode(); allowEventDispatch(); } @@ -335,6 +339,9 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce child->setParent(this); child->setPreviousSibling(prev.get()); child->setNextSibling(next); + child->updatePreviousNode(); + child->lastDescendantNode(true)->updateNextNode(); + allowEventDispatch(); childrenChanged(false, prev.get(), next, 1); @@ -362,12 +369,13 @@ bool ContainerNode::replaceChild(PassRefPtr<Node> newChild, Node* oldChild, Exce void ContainerNode::willRemove() { - Vector<RefPtr<Node>, 10> nodes; - nodes.reserveInitialCapacity(childNodeCount()); - for (Node* n = m_lastChild; n; n = n->previousSibling()) - nodes.append(n); - for (; nodes.size(); nodes.removeLast()) - nodes.last().get()->willRemove(); + Node* next; + Node* child = m_firstChild; + while (child) { + next = child->nextSibling(); + child->willRemove(); + child = next; + } Node::willRemove(); } @@ -468,6 +476,8 @@ void ContainerNode::removeBetween(Node* previousChild, Node* nextChild, Node* ol if (oldChild->attached()) oldChild->detach(); + Node* previousNode = oldChild->traversePreviousNodeFastPath(); + if (nextChild) nextChild->setPreviousSibling(previousChild); if (previousChild) @@ -480,6 +490,10 @@ void ContainerNode::removeBetween(Node* previousChild, Node* nextChild, Node* ol oldChild->setPreviousSibling(0); oldChild->setNextSibling(0); oldChild->setParent(0); + oldChild->setPreviousNode(0); + oldChild->lastDescendantNode(true)->setNextNode(0); + if (previousNode) + previousNode->updateNextNode(); allowEventDispatch(); } @@ -530,6 +544,8 @@ void ContainerNode::removeChildren() n->setPreviousSibling(0); n->setNextSibling(0); n->setParent(0); + n->lastDescendantNode(true)->setNextNode(0); + n->setPreviousNode(0); m_firstChild = next; if (n == m_lastChild) @@ -552,6 +568,7 @@ void ContainerNode::removeChildren() removedChild->detach(); } + updateNextNode(); allowEventDispatch(); // Dispatch a single post-removal mutation event denoting a modified subtree. @@ -621,6 +638,8 @@ bool ContainerNode::appendChild(PassRefPtr<Node> newChild, ExceptionCode& ec, bo } else m_firstChild = child; m_lastChild = child; + child->updatePreviousNode(); + child->lastDescendantNode(true)->updateNextNode(); allowEventDispatch(); // Send notification about the children change. @@ -658,6 +677,10 @@ void ContainerNode::parserAddChild(PassRefPtr<Node> newChild) Node* last = m_lastChild; // FIXME: This method should take a PassRefPtr. appendChildToContainer<Node, ContainerNode>(newChild.get(), this); + if (last) + last->updateNextNode(); + newChild->updatePreviousNode(); + newChild->lastDescendantNode(true)->updateNextNode(); allowEventDispatch(); // FIXME: Why doesn't this use notifyChildInserted(newChild) instead? @@ -1070,8 +1093,12 @@ static void dispatchChildInsertionEvents(Node* child) // dispatch the DOMNodeInsertedIntoDocument event to all descendants if (c->inDocument() && document->hasListenerType(Document::DOMNODEINSERTEDINTODOCUMENT_LISTENER)) { - for (; c; c = c->traverseNextNode(child)) + Node* last = child->lastDescendantNode(true); + for (; c; c = c->traverseNextNodeFastPath()) { c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeInsertedIntoDocumentEvent, false)); + if (last == c) + break; + } } } @@ -1092,8 +1119,12 @@ static void dispatchChildRemovalEvents(Node* child) // dispatch the DOMNodeRemovedFromDocument event to all descendants if (c->inDocument() && document->hasListenerType(Document::DOMNODEREMOVEDFROMDOCUMENT_LISTENER)) { - for (; c; c = c->traverseNextNode(child)) + Node* last = c->lastDescendantNode(true); + for (; c; c = c->traverseNextNodeFastPath()) { c->dispatchScopedEvent(MutationEvent::create(eventNames().DOMNodeRemovedFromDocumentEvent, false)); + if (last == c) + break; + } } } diff --git a/Source/WebCore/dom/ContainerNode.h b/Source/WebCore/dom/ContainerNode.h index 76eb1bd..ee8252e 100644 --- a/Source/WebCore/dom/ContainerNode.h +++ b/Source/WebCore/dom/ContainerNode.h @@ -170,6 +170,17 @@ inline Node* Node::lastChild() const return toContainerNode(this)->lastChild(); } +inline RenderObject* Node::previousRenderer() +{ + // FIXME: We should have the same O(N^2) avoidance as nextRenderer does + // however, when I tried adding it, several tests failed. + for (Node* n = previousSibling(); n; n = n->previousSibling()) { + if (n->renderer()) + return n->renderer(); + } + return 0; +} + } // namespace WebCore #endif // ContainerNode_h diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp index 063b8a2..f319cac 100644 --- a/Source/WebCore/dom/Document.cpp +++ b/Source/WebCore/dom/Document.cpp @@ -7,6 +7,9 @@ * 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) 2011, 2012 The Linux Foundation All rights reserved + * Copyright (C) 2011, 2012 Sony Ericsson Mobile Communications AB + * Copyright (C) 2012 Sony Mobile Communcations AB * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -107,6 +110,7 @@ #include "NestingLevelIncrementer.h" #include "NodeFilter.h" #include "NodeIterator.h" +#include "NodeRareData.h" #include "NodeWithIndex.h" #include "OverflowEvent.h" #include "Page.h" @@ -421,9 +425,13 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML) , m_sawElementsInKnownNamespaces(false) , m_usingGeolocation(false) , m_eventQueue(EventQueue::create(this)) + , m_documentRareData(0) #if ENABLE(WML) , m_containsWMLContent(false) #endif +#if ENABLE(WEBGL) && PLATFORM(ANDROID) + , m_containsWebGLContent(false) +#endif , m_weakReference(DocumentWeakReference::create(this)) , m_idAttributeName(idAttr) #if ENABLE(FULLSCREEN_API) @@ -567,6 +575,13 @@ Document::~Document() if (m_implementation) m_implementation->ownerDocumentDestroyed(); + + if (hasRareData()) { + ASSERT(m_documentRareData); + delete m_documentRareData; + m_documentRareData = 0; + clearFlag(HasRareDataFlag); + } } void Document::removedLastRef() @@ -1810,7 +1825,7 @@ void Document::removeAllEventListeners() if (DOMWindow* domWindow = this->domWindow()) domWindow->removeAllEventListeners(); - for (Node* node = firstChild(); node; node = node->traverseNextNode()) + for (Node* node = firstChild(); node; node = node->traverseNextNodeFastPath()) node->removeAllEventListeners(); } @@ -3842,11 +3857,12 @@ static inline bool isValidNameASCII(const UChar* characters, unsigned length) bool Document::isValidName(const String& name) { - unsigned length = name.length(); - if (!length) + if (name.isEmpty()) return false; - const UChar* characters = name.characters(); + StringImpl* impl = name.impl(); + const UChar* characters = impl->characters(); + unsigned length = impl->length(); return isValidNameASCII(characters, length) || isValidNameNonASCII(characters, length); } @@ -5026,15 +5042,15 @@ void Document::loadEventDelayTimerFired(Timer<Document>*) } #if ENABLE(REQUEST_ANIMATION_FRAME) -int Document::webkitRequestAnimationFrame(PassRefPtr<RequestAnimationFrameCallback> callback, Element* animationElement) +int Document::webkitRequestAnimationFrame(PassRefPtr<RequestAnimationFrameCallback> callback) { if (!m_scriptedAnimationController) m_scriptedAnimationController = ScriptedAnimationController::create(this); - return m_scriptedAnimationController->registerCallback(callback, animationElement); + return m_scriptedAnimationController->registerCallback(callback); } -void Document::webkitCancelRequestAnimationFrame(int id) +void Document::webkitCancelAnimationFrame(int id) { if (!m_scriptedAnimationController) return; @@ -5082,4 +5098,29 @@ DocumentLoader* Document::loader() const return loader; } +#if ENABLE(WEBGL) && PLATFORM(ANDROID) +void Document::suspendDocument() +{ + HashSet<Element*>::iterator end = m_documentSuspendCallbackElements.end(); + for (HashSet<Element*>::iterator i = m_documentSuspendCallbackElements.begin(); i != end; ++i) + (*i)->documentWasSuspended(); +} + +void Document::resumeDocument() +{ + HashSet<Element*>::iterator end = m_documentSuspendCallbackElements.end(); + for (HashSet<Element*>::iterator i = m_documentSuspendCallbackElements.begin(); i != end; ++i) + (*i)->documentWillResume(); +} + +void Document::registerForDocumentSuspendCallbacks(Element* e) +{ + m_documentSuspendCallbackElements.add(e); +} + +void Document::unregisterForDocumentSuspendCallbacks(Element* e) +{ + m_documentSuspendCallbackElements.remove(e); +} +#endif } // namespace WebCore diff --git a/Source/WebCore/dom/Document.h b/Source/WebCore/dom/Document.h index c4ccb9c..a51861b 100644 --- a/Source/WebCore/dom/Document.h +++ b/Source/WebCore/dom/Document.h @@ -6,6 +6,9 @@ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (c) 2011, 2012 The Linux Foundation All rights reserved + * Copyright (C) 2011, 2012 Sony Ericsson Mobile Communications AB + * Copyright (C) 2012 Sony Mobile Communcations AB * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -101,6 +104,7 @@ class MediaQueryMatcher; class MouseEventWithHitTestResults; class NodeFilter; class NodeIterator; +class NodeRareData; class Page; class PlatformMouseEvent; class ProcessingInstruction; @@ -1035,6 +1039,15 @@ public: void initializeWMLPageState(); #endif +#if ENABLE(WEBGL) && PLATFORM(ANDROID) + void setContainsWebGLContent(bool value) { m_containsWebGLContent = value; } + bool containsWebGLContent() const { return m_containsWebGLContent; } + void suspendDocument(); + void resumeDocument(); + void registerForDocumentSuspendCallbacks(Element*); + void unregisterForDocumentSuspendCallbacks(Element*); +#endif + bool containsValidityStyleRules() const { return m_containsValidityStyleRules; } void setContainsValidityStyleRules() { m_containsValidityStyleRules = true; } @@ -1085,8 +1098,8 @@ public: const DocumentTiming* timing() const { return &m_documentTiming; } #if ENABLE(REQUEST_ANIMATION_FRAME) - int webkitRequestAnimationFrame(PassRefPtr<RequestAnimationFrameCallback>, Element*); - void webkitCancelRequestAnimationFrame(int id); + int webkitRequestAnimationFrame(PassRefPtr<RequestAnimationFrameCallback>); + void webkitCancelAnimationFrame(int id); void serviceScriptedAnimations(DOMTimeStamp); #endif @@ -1097,12 +1110,14 @@ public: ContentSecurityPolicy* contentSecurityPolicy() { return m_contentSecurityPolicy.get(); } + NodeRareData* documentRareData() const { return m_documentRareData; }; + void setDocumentRareData(NodeRareData* rareData) { m_documentRareData = rareData; } + protected: Document(Frame*, const KURL&, bool isXHTML, bool isHTML); void clearXMLVersion() { m_xmlVersion = String(); } - private: friend class IgnoreDestructiveWriteCountIncrementer; @@ -1364,10 +1379,17 @@ private: RefPtr<EventQueue> m_eventQueue; + NodeRareData* m_documentRareData; + #if ENABLE(WML) bool m_containsWMLContent; #endif +#if ENABLE(WEBGL) && PLATFORM(ANDROID) + bool m_containsWebGLContent; + HashSet<Element*> m_documentSuspendCallbackElements; +#endif + RefPtr<DocumentWeakReference> m_weakReference; HashSet<MediaCanStartListener*> m_mediaCanStartListeners; @@ -1412,8 +1434,13 @@ inline Node::Node(Document* document, ConstructionType type) : m_document(document) , m_previous(0) , m_next(0) +#ifdef __ARM_USE_PLD + , m_prefetch(0) +#endif , m_renderer(0) , m_nodeFlags(type) + , m_previousNode(0) + , m_nextNode(0) { if (m_document) m_document->guardRef(); diff --git a/Source/WebCore/dom/DocumentOrderedMap.cpp b/Source/WebCore/dom/DocumentOrderedMap.cpp index 47268c4..73a0843 100644 --- a/Source/WebCore/dom/DocumentOrderedMap.cpp +++ b/Source/WebCore/dom/DocumentOrderedMap.cpp @@ -117,7 +117,7 @@ inline Element* DocumentOrderedMap::get(AtomicStringImpl* key, const TreeScope* if (m_duplicateCounts.contains(key)) { // We know there's at least one node that matches; iterate to find the first one. - for (Node* node = scope->firstChild(); node; node = node->traverseNextNode()) { + for (Node* node = scope->firstChild(); node; node = node->traverseNextNodeFastPath()) { if (!node->isElementNode()) continue; element = static_cast<Element*>(node); diff --git a/Source/WebCore/dom/DynamicNodeList.cpp b/Source/WebCore/dom/DynamicNodeList.cpp index 23664e8..bba1678 100644 --- a/Source/WebCore/dom/DynamicNodeList.cpp +++ b/Source/WebCore/dom/DynamicNodeList.cpp @@ -3,6 +3,7 @@ * (C) 1999 Antti Koivisto (koivisto@kde.org) * (C) 2001 Dirk Mueller (mueller@kde.org) * Copyright (C) 2004, 2006, 2007, 2008, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2012 The Linux Foundation 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 @@ -56,8 +57,18 @@ unsigned DynamicNodeList::length() const unsigned length = 0; - for (Node* n = m_rootNode->firstChild(); n; n = n->traverseNextNode(m_rootNode.get())) - length += n->isElementNode() && nodeMatches(static_cast<Element*>(n)); + Node* lastNode = m_rootNode->lastDescendantNode(); + Vector<Node* >& cachedNodes = m_caches->cachedNodes; + for (Node* n = m_rootNode->firstChild(); n; n = n->traverseNextNodeFastPath()) { + if (n->isElementNode() && nodeMatches(static_cast<Element*>(n))) { + if (length >= cachedNodes.size()) + cachedNodes.resize(length + 1); + cachedNodes.data()[length] = n; + length ++; + } + if (n == lastNode) + break; + } m_caches->cachedLength = length; m_caches->isLengthCacheValid = true; @@ -68,7 +79,9 @@ unsigned DynamicNodeList::length() const Node* DynamicNodeList::itemForwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const { ASSERT(remainingOffset >= 0); - for (Node* n = start; n; n = n->traverseNextNode(m_rootNode.get())) { + if (!m_caches->lastDecendantOfRoot) + m_caches->lastDecendantOfRoot = m_rootNode->lastDescendantNode(); + for (Node* n = start; n; n = n->traverseNextNodeFastPath()) { if (n->isElementNode() && nodeMatches(static_cast<Element*>(n))) { if (!remainingOffset) { m_caches->lastItem = n; @@ -78,6 +91,8 @@ Node* DynamicNodeList::itemForwardsFromCurrent(Node* start, unsigned offset, int } --remainingOffset; } + if (n == m_caches->lastDecendantOfRoot) + break; } return 0; // no matching node in this subtree @@ -103,6 +118,14 @@ Node* DynamicNodeList::itemBackwardsFromCurrent(Node* start, unsigned offset, in Node* DynamicNodeList::item(unsigned offset) const { + Node* result; + Vector<Node* >& cachedNodes = m_caches->cachedNodes; + if (offset < cachedNodes.size()) { + result = cachedNodes[offset]; + if (result) + return result; + } + int remainingOffset = offset; Node* start = m_rootNode->firstChild(); if (m_caches->isItemCacheValid) { @@ -115,8 +138,16 @@ Node* DynamicNodeList::item(unsigned offset) const } if (remainingOffset < 0) - return itemBackwardsFromCurrent(start, offset, remainingOffset); - return itemForwardsFromCurrent(start, offset, remainingOffset); + result = itemBackwardsFromCurrent(start, offset, remainingOffset); + else + result = itemForwardsFromCurrent(start, offset, remainingOffset); + + if (result) { + if (offset >= cachedNodes.size()) + cachedNodes.resize(offset + 1); + cachedNodes.data()[offset] = result; + } + return result; } Node* DynamicNodeList::itemWithName(const AtomicString& elementId) const @@ -159,6 +190,7 @@ void DynamicNodeList::invalidateCache() DynamicNodeList::Caches::Caches() : lastItem(0) + , lastDecendantOfRoot(0) , isLengthCacheValid(false) , isItemCacheValid(false) { @@ -172,8 +204,10 @@ PassRefPtr<DynamicNodeList::Caches> DynamicNodeList::Caches::create() void DynamicNodeList::Caches::reset() { lastItem = 0; + lastDecendantOfRoot = 0; isLengthCacheValid = false; - isItemCacheValid = false; + isItemCacheValid = false; + cachedNodes.clear(); } } // namespace WebCore diff --git a/Source/WebCore/dom/DynamicNodeList.h b/Source/WebCore/dom/DynamicNodeList.h index 9c8f3cc..c8b6ca2 100644 --- a/Source/WebCore/dom/DynamicNodeList.h +++ b/Source/WebCore/dom/DynamicNodeList.h @@ -28,6 +28,12 @@ #include <wtf/RefCounted.h> #include <wtf/Forward.h> #include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace WTF { + // Properties in Vector can be initialized with memset and moved using memcpy. + template<> struct VectorTraits<WebCore::Node*> : SimpleClassVectorTraits { }; +} namespace WebCore { @@ -42,9 +48,11 @@ namespace WebCore { unsigned cachedLength; Node* lastItem; + Node* lastDecendantOfRoot; unsigned lastItemOffset; bool isLengthCacheValid : 1; bool isItemCacheValid : 1; + Vector<Node* > cachedNodes; protected: Caches(); }; diff --git a/Source/WebCore/dom/Element.cpp b/Source/WebCore/dom/Element.cpp index 5fb6cdc..4b9de49 100644 --- a/Source/WebCore/dom/Element.cpp +++ b/Source/WebCore/dom/Element.cpp @@ -622,7 +622,7 @@ static inline bool shouldIgnoreAttributeCase(const Element* e) return e && e->document()->isHTMLDocument() && e->isHTMLElement(); } -const AtomicString& Element::getAttribute(const String& name) const +const AtomicString& Element::getAttribute(const AtomicString& name) const { bool ignoreCase = shouldIgnoreAttributeCase(this); @@ -645,7 +645,7 @@ const AtomicString& Element::getAttribute(const String& name) const return nullAtom; } -const AtomicString& Element::getAttributeNS(const String& namespaceURI, const String& localName) const +const AtomicString& Element::getAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const { return getAttribute(QualifiedName(nullAtom, localName, namespaceURI)); } @@ -1471,11 +1471,11 @@ void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicStrin setAttribute(qName, value, ec); } -void Element::removeAttribute(const String& name, ExceptionCode& ec) +void Element::removeAttribute(const AtomicString& name, ExceptionCode& ec) { InspectorInstrumentation::willModifyDOMAttr(document(), this); - String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name; + AtomicString localName = shouldIgnoreAttributeCase(this) ? name.lower() : name; if (m_attributeMap) { m_attributeMap->removeNamedItem(localName, ec); @@ -1486,21 +1486,21 @@ void Element::removeAttribute(const String& name, ExceptionCode& ec) InspectorInstrumentation::didModifyDOMAttr(document(), this); } -void Element::removeAttributeNS(const String& namespaceURI, const String& localName, ExceptionCode& ec) +void Element::removeAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName, ExceptionCode& ec) { removeAttribute(QualifiedName(nullAtom, localName, namespaceURI), ec); } -PassRefPtr<Attr> Element::getAttributeNode(const String& name) +PassRefPtr<Attr> Element::getAttributeNode(const AtomicString& name) { NamedNodeMap* attrs = attributes(true); if (!attrs) return 0; - String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name; + AtomicString localName = shouldIgnoreAttributeCase(this) ? name.lower() : name; return static_pointer_cast<Attr>(attrs->getNamedItem(localName)); } -PassRefPtr<Attr> Element::getAttributeNodeNS(const String& namespaceURI, const String& localName) +PassRefPtr<Attr> Element::getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName) { NamedNodeMap* attrs = attributes(true); if (!attrs) @@ -1508,7 +1508,7 @@ PassRefPtr<Attr> Element::getAttributeNodeNS(const String& namespaceURI, const S return static_pointer_cast<Attr>(attrs->getNamedItem(QualifiedName(nullAtom, localName, namespaceURI))); } -bool Element::hasAttribute(const String& name) const +bool Element::hasAttribute(const AtomicString& name) const { NamedNodeMap* attrs = attributes(true); if (!attrs) @@ -1516,11 +1516,11 @@ bool Element::hasAttribute(const String& name) const // This call to String::lower() seems to be required but // there may be a way to remove it. - String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name; + AtomicString localName = shouldIgnoreAttributeCase(this) ? name.lower() : name; return attrs->getAttributeItem(localName, false); } -bool Element::hasAttributeNS(const String& namespaceURI, const String& localName) const +bool Element::hasAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const { NamedNodeMap* attrs = attributes(true); if (!attrs) diff --git a/Source/WebCore/dom/Element.h b/Source/WebCore/dom/Element.h index d269dbe..79815dd 100644 --- a/Source/WebCore/dom/Element.h +++ b/Source/WebCore/dom/Element.h @@ -4,6 +4,8 @@ * (C) 2001 Peter Kelly (pmk@post.com) * (C) 2001 Dirk Mueller (mueller@kde.org) * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2012 Sony Ericsson Mobile Communications AB + * Copyright (C) 2012 Sony Mobile Communications AB * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -126,11 +128,11 @@ public: bool hasAttributes() const; - bool hasAttribute(const String& name) const; - bool hasAttributeNS(const String& namespaceURI, const String& localName) const; + bool hasAttribute(const AtomicString& name) const; + bool hasAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const; - const AtomicString& getAttribute(const String& name) const; - const AtomicString& getAttributeNS(const String& namespaceURI, const String& localName) const; + const AtomicString& getAttribute(const AtomicString& name) const; + const AtomicString& getAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const; void setAttribute(const AtomicString& name, const AtomicString& value, ExceptionCode&); void setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionCode&, FragmentScriptingPermission = FragmentScriptingAllowed); @@ -174,11 +176,11 @@ public: // Returns the absolute bounding box translated into screen coordinates: IntRect screenRect() const; - void removeAttribute(const String& name, ExceptionCode&); - void removeAttributeNS(const String& namespaceURI, const String& localName, ExceptionCode&); + void removeAttribute(const AtomicString& name, ExceptionCode&); + void removeAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName, ExceptionCode&); - PassRefPtr<Attr> getAttributeNode(const String& name); - PassRefPtr<Attr> getAttributeNodeNS(const String& namespaceURI, const String& localName); + PassRefPtr<Attr> getAttributeNode(const AtomicString& name); + PassRefPtr<Attr> getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName); PassRefPtr<Attr> setAttributeNode(Attr*, ExceptionCode&); PassRefPtr<Attr> setAttributeNodeNS(Attr*, ExceptionCode&); PassRefPtr<Attr> removeAttributeNode(Attr*, ExceptionCode&); @@ -351,6 +353,11 @@ public: PassRefPtr<WebKitAnimationList> webkitGetAnimations() const; +#if ENABLE(WEBGL) && PLATFORM(ANDROID) + virtual void documentWasSuspended() {} + virtual void documentWillResume() {} +#endif + protected: Element(const QualifiedName& tagName, Document* document, ConstructionType type) : ContainerNode(document, type) diff --git a/Source/WebCore/dom/NamedNodeMap.cpp b/Source/WebCore/dom/NamedNodeMap.cpp index 6fa30bf..253bc53 100644 --- a/Source/WebCore/dom/NamedNodeMap.cpp +++ b/Source/WebCore/dom/NamedNodeMap.cpp @@ -54,7 +54,7 @@ NamedNodeMap::~NamedNodeMap() detachAttributesFromElement(); } -PassRefPtr<Node> NamedNodeMap::getNamedItem(const String& name) const +PassRefPtr<Node> NamedNodeMap::getNamedItem(const AtomicString& name) const { Attribute* a = getAttributeItem(name, shouldIgnoreAttributeCase(m_element)); if (!a) @@ -63,12 +63,12 @@ PassRefPtr<Node> NamedNodeMap::getNamedItem(const String& name) const return a->createAttrIfNeeded(m_element); } -PassRefPtr<Node> NamedNodeMap::getNamedItemNS(const String& namespaceURI, const String& localName) const +PassRefPtr<Node> NamedNodeMap::getNamedItemNS(const AtomicString& namespaceURI, const AtomicString& localName) const { return getNamedItem(QualifiedName(nullAtom, localName, namespaceURI)); } -PassRefPtr<Node> NamedNodeMap::removeNamedItem(const String& name, ExceptionCode& ec) +PassRefPtr<Node> NamedNodeMap::removeNamedItem(const AtomicString& name, ExceptionCode& ec) { Attribute* a = getAttributeItem(name, shouldIgnoreAttributeCase(m_element)); if (!a) { @@ -79,7 +79,7 @@ PassRefPtr<Node> NamedNodeMap::removeNamedItem(const String& name, ExceptionCode return removeNamedItem(a->name(), ec); } -PassRefPtr<Node> NamedNodeMap::removeNamedItemNS(const String& namespaceURI, const String& localName, ExceptionCode& ec) +PassRefPtr<Node> NamedNodeMap::removeNamedItemNS(const AtomicString& namespaceURI, const AtomicString& localName, ExceptionCode& ec) { return removeNamedItem(QualifiedName(nullAtom, localName, namespaceURI), ec); } @@ -171,7 +171,7 @@ void NamedNodeMap::copyAttributesToVector(Vector<RefPtr<Attribute> >& copy) copy = m_attributes; } -Attribute* NamedNodeMap::getAttributeItemSlowCase(const String& name, bool shouldIgnoreAttributeCase) const +Attribute* NamedNodeMap::getAttributeItemSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const { unsigned len = length(); diff --git a/Source/WebCore/dom/NamedNodeMap.h b/Source/WebCore/dom/NamedNodeMap.h index c3c2cd9..f4aedb0 100644 --- a/Source/WebCore/dom/NamedNodeMap.h +++ b/Source/WebCore/dom/NamedNodeMap.h @@ -46,11 +46,11 @@ public: // Public DOM interface. - PassRefPtr<Node> getNamedItem(const String& name) const; - PassRefPtr<Node> removeNamedItem(const String& name, ExceptionCode&); + PassRefPtr<Node> getNamedItem(const AtomicString& name) const; + PassRefPtr<Node> removeNamedItem(const AtomicString& name, ExceptionCode&); - PassRefPtr<Node> getNamedItemNS(const String& namespaceURI, const String& localName) const; - PassRefPtr<Node> removeNamedItemNS(const String& namespaceURI, const String& localName, ExceptionCode&); + PassRefPtr<Node> getNamedItemNS(const AtomicString& namespaceURI, const AtomicString& localName) const; + PassRefPtr<Node> removeNamedItemNS(const AtomicString& namespaceURI, const AtomicString& localName, ExceptionCode&); PassRefPtr<Node> getNamedItem(const QualifiedName& name) const; PassRefPtr<Node> removeNamedItem(const QualifiedName& name, ExceptionCode&); @@ -111,8 +111,8 @@ private: void detachAttributesFromElement(); void detachFromElement(); - Attribute* getAttributeItem(const String& name, bool shouldIgnoreAttributeCase) const; - Attribute* getAttributeItemSlowCase(const String& name, bool shouldIgnoreAttributeCase) const; + Attribute* getAttributeItem(const AtomicString& name, bool shouldIgnoreAttributeCase) const; + Attribute* getAttributeItemSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const; void clearAttributes(); int declCount() const; @@ -135,7 +135,7 @@ inline Attribute* NamedNodeMap::getAttributeItem(const QualifiedName& name) cons // We use a boolean parameter instead of calling shouldIgnoreAttributeCase so that the caller // can tune the behavior (hasAttribute is case sensitive whereas getAttribute is not). -inline Attribute* NamedNodeMap::getAttributeItem(const String& name, bool shouldIgnoreAttributeCase) const +inline Attribute* NamedNodeMap::getAttributeItem(const AtomicString& name, bool shouldIgnoreAttributeCase) const { unsigned len = length(); bool doSlowCheck = shouldIgnoreAttributeCase; diff --git a/Source/WebCore/dom/Node.cpp b/Source/WebCore/dom/Node.cpp index da4312c..facb694 100644 --- a/Source/WebCore/dom/Node.cpp +++ b/Source/WebCore/dom/Node.cpp @@ -5,6 +5,7 @@ * 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) 2012 The Linux Foundation 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 @@ -130,6 +131,8 @@ namespace WebCore { using namespace HTMLNames; +const int Node::cPrefetchTargetDepth = 7; + bool Node::isSupported(const String& feature, const String& version) { return DOMImplementation::hasFeature(feature, version); @@ -391,7 +394,7 @@ Node::~Node() else { if (m_document && rareData()->nodeLists()) m_document->removeNodeListCache(); - + NodeRareData::NodeRareDataMap& dataMap = NodeRareData::rareDataMap(); NodeRareData::NodeRareDataMap::iterator it = dataMap.find(this); ASSERT(it != dataMap.end()); @@ -409,6 +412,8 @@ Node::~Node() m_previous->setNextSibling(0); if (m_next) m_next->setPreviousSibling(0); + m_nextNode = 0; + m_previousNode = 0; if (m_document) m_document->guardDeref(); @@ -517,16 +522,21 @@ void Node::setTreeScopeRecursively(TreeScope* newTreeScope) if (currentDocument && currentDocument != newDocument) currentDocument->incDOMTreeVersion(); - for (Node* node = this; node; node = node->traverseNextNode(this)) { + Node* last = this->lastDescendantNode(true); + for (Node* node = this; node; node = node->traverseNextNodeFastPath()) { node->setTreeScope(newTreeScope); // FIXME: Once shadow scopes are landed, update parent scope, etc. + if (last == node) + break; } } NodeRareData* Node::rareData() const { ASSERT(hasRareData()); - return NodeRareData::rareDataFromMap(this); + NodeRareData* data = isDocumentNode() ? static_cast<const Document*>(this)->documentRareData() : NodeRareData::rareDataFromMap(this); + ASSERT(data); + return data; } NodeRareData* Node::ensureRareData() @@ -534,9 +544,15 @@ NodeRareData* Node::ensureRareData() if (hasRareData()) return rareData(); - ASSERT(!NodeRareData::rareDataMap().contains(this)); NodeRareData* data = createRareData(); - NodeRareData::rareDataMap().set(this, data); + if (isDocumentNode()) { + // Fast path for a Document. A Document knows a pointer to NodeRareData. + ASSERT(!static_cast<Document*>(this)->documentRareData()); + static_cast<Document*>(this)->setDocumentRareData(data); + } else { + ASSERT(!NodeRareData::rareDataMap().contains(this)); + NodeRareData::rareDataMap().set(this, data); + } setFlag(HasRareDataFlag); return data; } @@ -548,18 +564,22 @@ NodeRareData* Node::createRareData() Element* Node::shadowHost() const { - return toElement(getFlag(IsShadowRootFlag) ? parent() : 0); + return toElement(isShadowRoot() ? parent() : 0); } void Node::setShadowHost(Element* host) { ASSERT(!parentNode() && !isSVGShadowRoot()); if (host) - setFlag(IsShadowRootFlag); + setFlag(IsShadowRootOrSVGShadowRootFlag); else - clearFlag(IsShadowRootFlag); + clearFlag(IsShadowRootOrSVGShadowRootFlag); setParent(host); + updatePreviousNode(); + lastDescendantNode(true)->updateNextNode(); + if (host) + host->updateNextNode(); } InputElement* Node::toInputElement() @@ -607,14 +627,9 @@ void Node::setNodeValue(const String& /*nodeValue*/, ExceptionCode& ec) PassRefPtr<NodeList> Node::childNodes() { - NodeRareData* data = ensureRareData(); - if (!data->nodeLists()) { - data->setNodeLists(NodeListsNodeData::create()); - if (document()) - document()->addNodeListCache(); - } + NodeListsNodeData* data = ensureRareData()->ensureNodeLists(this); - return ChildNodeList::create(this, data->nodeLists()->m_childNodeListCaches.get()); + return ChildNodeList::create(this, data->m_childNodeListCaches.get()); } Node *Node::lastDescendant() const @@ -862,12 +877,15 @@ void Node::setDocumentRecursively(Document* newDocument) { ASSERT(document() != newDocument); - for (Node* node = this; node; node = node->traverseNextNode(this)) { + Node* last = this->lastDescendantNode(true); + for (Node* node = this; node; node = node->traverseNextNodeFastPath()) { node->setDocument(newDocument); - if (!node->isElementNode()) - continue; - if (Node* shadow = shadowRoot(node)) - shadow->setDocumentRecursively(newDocument); + if (node->isElementNode()) { + if (Node* shadow = shadowRoot(node)) + shadow->setDocumentRecursively(newDocument); + } + if (node == last) + break; } } @@ -911,12 +929,15 @@ void Node::setNeedsStyleRecalc(StyleChangeType changeType) void Node::lazyAttach(ShouldSetAttached shouldSetAttached) { - for (Node* n = this; n; n = n->traverseNextNode(this)) { + Node* last = this->lastDescendantNode(true); + for (Node* n = this; n; n = n->traverseNextNodeFastPath()) { if (n->firstChild()) n->setChildNeedsStyleRecalc(); n->setStyleChange(FullStyleChange); if (shouldSetAttached == SetAttached) n->setAttached(); + if (n == last) + break; } markAncestorsWithChildNeedsStyleRecalc(); } @@ -1092,7 +1113,7 @@ void Node::removeCachedNameNodeList(NameNodeList* list, const String& nodeName) data->m_nameNodeListCache.remove(nodeName); } -void Node::removeCachedTagNodeList(TagNodeList* list, const QualifiedName& name) +void Node::removeCachedTagNodeList(TagNodeList* list, const AtomicString& name) { ASSERT(rareData()); ASSERT(rareData()->nodeLists()); @@ -1103,6 +1124,17 @@ void Node::removeCachedTagNodeList(TagNodeList* list, const QualifiedName& name) data->m_tagNodeListCache.remove(name.impl()); } +void Node::removeCachedTagNodeListNS(TagNodeListNS* list, const QualifiedName& name) +{ + ASSERT(rareData()); + ASSERT(rareData()->nodeLists()); + ASSERT_UNUSED(list, list->hasOwnCaches()); + + NodeListsNodeData* data = rareData()->nodeLists(); + ASSERT_UNUSED(list, list == data->m_tagNodeListCacheNS.get(name.impl())); + data->m_tagNodeListCacheNS.remove(name.impl()); +} + void Node::removeCachedLabelsNodeList(DynamicNodeList* list) { ASSERT(rareData()); @@ -1115,12 +1147,15 @@ void Node::removeCachedLabelsNodeList(DynamicNodeList* list) Node* Node::traverseNextNode(const Node* stayWithin) const { - if (firstChild()) - return firstChild(); + prefetchTarget(); + Node* fc = firstChild(); + if (fc) + return fc; if (this == stayWithin) return 0; - if (nextSibling()) - return nextSibling(); + Node* ns = nextSibling(); + if (ns) + return ns; const Node *n = this; while (n && !n->nextSibling() && (!stayWithin || n->parentNode() != stayWithin)) n = n->parentNode(); @@ -1129,15 +1164,54 @@ Node* Node::traverseNextNode(const Node* stayWithin) const return 0; } +Node* Node::lastDescendantNode(bool includeThis) const +{ + Node* n = lastChild(); + if (!n && includeThis) + return const_cast<Node*>(this); + + Node* p = n; + while(n) { + p = n; + n = n->lastChild(); + } + return p; +} + +void Node::updatePrevNextNodesInSubtree() +{ + Node* n = firstChild(); + Node* next; + while(n) { + next = n->traverseNextNode(this); + if (next) { + n->setNextNode(next); + next->setPreviousNode(n); + } else { + next = n->traverseNextNode(); + n->setNextNode(next); + if (next) + next->setPreviousNode(n); + break; + } + n = next; + } + updateNextNode(); +} + Node* Node::traverseNextSibling(const Node* stayWithin) const { if (this == stayWithin) return 0; - if (nextSibling()) - return nextSibling(); + prefetchTarget(); + Node* ns = nextSibling(); + if (ns) + return ns; const Node *n = this; - while (n && !n->nextSibling() && (!stayWithin || n->parentNode() != stayWithin)) + while (n && !n->nextSibling() && (!stayWithin || n->parentNode() != stayWithin)) { + n->prefetchTarget(); n = n->parentNode(); + } if (n) return n->nextSibling(); return 0; @@ -1157,10 +1231,11 @@ Node* Node::traversePreviousNode(const Node* stayWithin) const { if (this == stayWithin) return 0; - if (previousSibling()) { - Node *n = previousSibling(); - while (n->lastChild()) - n = n->lastChild(); + Node *n = previousSibling(); + if (n) { + Node* lastChild; + while ((lastChild = n->lastChild())) + n = lastChild; return n; } return parentNode(); @@ -1168,12 +1243,12 @@ Node* Node::traversePreviousNode(const Node* stayWithin) const Node* Node::traversePreviousNodePostOrder(const Node* stayWithin) const { - if (lastChild()) - return lastChild(); + if (Node* lc = lastChild()) + return lc; if (this == stayWithin) return 0; - if (previousSibling()) - return previousSibling(); + if (Node* ps = previousSibling()) + return ps; const Node *n = this; while (n && !n->previousSibling() && (!stayWithin || n->parentNode() != stayWithin)) n = n->parentNode(); @@ -1186,8 +1261,8 @@ Node* Node::traversePreviousSiblingPostOrder(const Node* stayWithin) const { if (this == stayWithin) return 0; - if (previousSibling()) - return previousSibling(); + if (Node* ps = previousSibling()) + return ps; const Node *n = this; while (n && !n->previousSibling() && (!stayWithin || n->parentNode() != stayWithin)) n = n->parentNode(); @@ -1333,14 +1408,20 @@ void Node::attach() // FIXME: This is O(N^2) for the innerHTML case, where all children are replaced at once (and not attached). // If this node got a renderer it may be the previousRenderer() of sibling text nodes and thus affect the // result of Text::rendererIsNeeded() for those nodes. - if (renderer()) { + RenderObject* renderer = this->renderer(); + if (renderer) { for (Node* next = nextSibling(); next; next = next->nextSibling()) { if (next->renderer()) break; if (!next->attached()) break; // Assume this means none of the following siblings are attached. - if (next->isTextNode()) + if (next->isTextNode()) { + static_cast<Text*>(next)->setPreviousRenderer(renderer); next->createRendererIfNeeded(); + if (next->renderer()) + renderer = next->renderer(); + static_cast<Text*>(next)->setPreviousRenderer(0); + } } } @@ -1366,23 +1447,7 @@ void Node::detach() if (inActiveChain()) doc->activeChainNodeDetached(this); - clearFlag(IsActiveFlag); - clearFlag(IsHoveredFlag); - clearFlag(InActiveChainFlag); - clearFlag(IsAttachedFlag); - - clearFlag(InDetachFlag); -} - -RenderObject* Node::previousRenderer() -{ - // FIXME: We should have the same O(N^2) avoidance as nextRenderer does - // however, when I tried adding it, several tests failed. - for (Node* n = previousSibling(); n; n = n->previousSibling()) { - if (n->renderer()) - return n->renderer(); - } - return 0; + clearFlag(NodeDetachClearFlags); } RenderObject* Node::nextRenderer() @@ -1697,44 +1762,45 @@ bool Node::inSameContainingBlockFlowElement(Node *n) PassRefPtr<NodeList> Node::getElementsByTagName(const AtomicString& name) { - return getElementsByTagNameNS(starAtom, name); + if (name.isNull()) + return 0; + + NodeListsNodeData* data = ensureRareData()->ensureNodeLists(this); + + AtomicString localNameAtom = document()->isHTMLDocument() ? name.lower() : name; + + pair<NodeListsNodeData::TagNodeListCache::iterator, bool> result = data->m_tagNodeListCache.add(localNameAtom.impl(), 0); + if (!result.second) + return PassRefPtr<TagNodeList>(result.first->second); + + RefPtr<TagNodeList> list = TagNodeList::create(this, localNameAtom); + result.first->second = list.get(); + return list.release(); } PassRefPtr<NodeList> Node::getElementsByTagNameNS(const AtomicString& namespaceURI, const AtomicString& localName) { if (localName.isNull()) return 0; - - NodeRareData* data = ensureRareData(); - if (!data->nodeLists()) { - data->setNodeLists(NodeListsNodeData::create()); - document()->addNodeListCache(); - } - String name = localName; - if (document()->isHTMLDocument()) - name = localName.lower(); - - AtomicString localNameAtom = name; - - pair<NodeListsNodeData::TagNodeListCache::iterator, bool> result = data->nodeLists()->m_tagNodeListCache.add(QualifiedName(nullAtom, localNameAtom, namespaceURI).impl(), 0); + NodeListsNodeData* data = ensureRareData()->ensureNodeLists(this); + + AtomicString localNameAtom = document()->isHTMLDocument() ? localName.lower() : localName; + + pair<NodeListsNodeData::TagNodeListCacheNS::iterator, bool> result = data->m_tagNodeListCacheNS.add(QualifiedName(nullAtom, localNameAtom, namespaceURI).impl(), 0); if (!result.second) - return PassRefPtr<TagNodeList>(result.first->second); - - RefPtr<TagNodeList> list = TagNodeList::create(this, namespaceURI.isEmpty() ? nullAtom : namespaceURI, localNameAtom); + return PassRefPtr<TagNodeListNS>(result.first->second); + + RefPtr<TagNodeListNS> list = TagNodeListNS::create(this, namespaceURI.isEmpty() ? nullAtom : namespaceURI, localNameAtom); result.first->second = list.get(); return list.release(); } PassRefPtr<NodeList> Node::getElementsByName(const String& elementName) { - NodeRareData* data = ensureRareData(); - if (!data->nodeLists()) { - data->setNodeLists(NodeListsNodeData::create()); - document()->addNodeListCache(); - } + NodeListsNodeData* data = ensureRareData()->ensureNodeLists(this); - pair<NodeListsNodeData::NameNodeListCache::iterator, bool> result = data->nodeLists()->m_nameNodeListCache.add(elementName, 0); + pair<NodeListsNodeData::NameNodeListCache::iterator, bool> result = data->m_nameNodeListCache.add(elementName, 0); if (!result.second) return PassRefPtr<NodeList>(result.first->second); @@ -1745,13 +1811,9 @@ PassRefPtr<NodeList> Node::getElementsByName(const String& elementName) PassRefPtr<NodeList> Node::getElementsByClassName(const String& classNames) { - NodeRareData* data = ensureRareData(); - if (!data->nodeLists()) { - data->setNodeLists(NodeListsNodeData::create()); - document()->addNodeListCache(); - } + NodeListsNodeData* data = ensureRareData()->ensureNodeLists(this); - pair<NodeListsNodeData::ClassNodeListCache::iterator, bool> result = data->nodeLists()->m_classNodeListCache.add(classNames, 0); + pair<NodeListsNodeData::ClassNodeListCache::iterator, bool> result = data->m_classNodeListCache.add(classNames, 0); if (!result.second) return PassRefPtr<NodeList>(result.first->second); @@ -1794,7 +1856,8 @@ PassRefPtr<Element> Node::querySelector(const String& selectors, ExceptionCode& } // FIXME: We can speed this up by implementing caching similar to the one use by getElementById - for (Node* n = firstChild(); n; n = n->traverseNextNode(this)) { + Node* last = lastDescendantNode(); + for (Node* n = firstChild(); n; n = n->traverseNextNodeFastPath()) { if (n->isElementNode()) { Element* element = static_cast<Element*>(n); for (CSSSelector* selector = querySelectorList.first(); selector; selector = CSSSelectorList::next(selector)) { @@ -1802,6 +1865,8 @@ PassRefPtr<Element> Node::querySelector(const String& selectors, ExceptionCode& return element; } } + if (n == last) + break; } return 0; @@ -2429,6 +2494,9 @@ void NodeListsNodeData::invalidateCaches() if (m_labelsNodeListCache) m_labelsNodeListCache->invalidateCache(); + TagNodeListCacheNS::const_iterator tagCacheEndNS = m_tagNodeListCacheNS.end(); + for (TagNodeListCacheNS::const_iterator it = m_tagNodeListCacheNS.begin(); it != tagCacheEndNS; ++it) + it->second->invalidateCache(); TagNodeListCache::const_iterator tagCacheEnd = m_tagNodeListCache.end(); for (TagNodeListCache::const_iterator it = m_tagNodeListCache.begin(); it != tagCacheEnd; ++it) it->second->invalidateCache(); @@ -2456,6 +2524,12 @@ bool NodeListsNodeData::isEmpty() const if (m_childNodeListCaches->refCount()) return false; + TagNodeListCacheNS::const_iterator tagCacheEndNS = m_tagNodeListCacheNS.end(); + for (TagNodeListCacheNS::const_iterator it = m_tagNodeListCacheNS.begin(); it != tagCacheEndNS; ++it) { + if (it->second->refCount()) + return false; + } + TagNodeListCache::const_iterator tagCacheEnd = m_tagNodeListCache.end(); for (TagNodeListCache::const_iterator it = m_tagNodeListCache.begin(); it != tagCacheEnd; ++it) { if (it->second->refCount()) diff --git a/Source/WebCore/dom/Node.h b/Source/WebCore/dom/Node.h index 76355c3..d75d064 100644 --- a/Source/WebCore/dom/Node.h +++ b/Source/WebCore/dom/Node.h @@ -4,6 +4,7 @@ * (C) 2001 Dirk Mueller (mueller@kde.org) * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * Copyright (C) 2012 The Linux Foundation 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 @@ -75,6 +76,7 @@ class RenderStyle; class SVGUseElement; #endif class TagNodeList; +class TagNodeListNS; class TreeScope; typedef int ExceptionCode; @@ -121,6 +123,8 @@ public: DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20, }; + static const int cPrefetchTargetDepth; + static bool isSupported(const String& feature, const String& version); static void startIgnoringLeaks(); @@ -143,8 +147,8 @@ public: virtual NodeType nodeType() const = 0; ContainerNode* parentNode() const; Element* parentElement() const; - Node* previousSibling() const { return m_previous; } - Node* nextSibling() const { return m_next; } + ALWAYS_INLINE Node* previousSibling() const { return m_previous; } + ALWAYS_INLINE Node* nextSibling() const { return m_next; } PassRefPtr<NodeList> childNodes(); Node* firstChild() const; Node* lastChild() const; @@ -187,14 +191,14 @@ public: // Other methods (not part of DOM) - bool isElementNode() const { return getFlag(IsElementFlag); } - bool isContainerNode() const { return getFlag(IsContainerFlag); } + ALWAYS_INLINE bool isElementNode() const { return getFlag(IsElementFlag); } + ALWAYS_INLINE bool isContainerNode() const { return getFlag(IsContainerFlag); } bool isTextNode() const { return getFlag(IsTextFlag); } bool isHTMLElement() const { return getFlag(IsHTMLFlag); } - bool isSVGElement() const { return getFlag(IsSVGFlag); } - virtual bool isSVGShadowRoot() const { return false; } + ALWAYS_INLINE bool isSVGElement() const { return getFlag(IsSVGFlag); } + ALWAYS_INLINE bool isSVGShadowRoot() const { return getFlag(IsShadowRootOrSVGShadowRootFlag) && isSVGElement(); } #if ENABLE(SVG) SVGUseElement* svgShadowHost() const; #endif @@ -213,7 +217,7 @@ public: bool isCommentNode() const { return getFlag(IsCommentFlag); } virtual bool isCharacterDataNode() const { return false; } bool isDocumentNode() const; - bool isShadowRoot() const { return getFlag(IsShadowRootFlag); } + bool isShadowRoot() const { return getFlag(IsShadowRootOrSVGShadowRootFlag) && !isSVGElement(); } // FIXME: Remove this when all shadow roots are ShadowRoots. virtual bool isShadowBoundary() const { return false; } virtual bool canHaveLightChildRendererWithShadow() const { return false; } @@ -240,7 +244,30 @@ public: // These low-level calls give the caller responsibility for maintaining the integrity of the tree. void setPreviousSibling(Node* previous) { m_previous = previous; } +#ifdef __ARM_USE_PLD + ALWAYS_INLINE void updatePrefetchTarget() { + if (m_next) { + int skew; + Node* from = this; + Node* n = from->traversePreviousNodePostOrder(); + for (skew = cPrefetchTargetDepth - 1; skew && n; skew--) { + from = n; + n = n->traversePreviousNodePostOrder(); + } + from->setPrefetchTarget(m_next); + } + } + void setPrefetchTarget(Node *prefetch) { m_prefetch = prefetch; } + void setNextSibling(Node* next) { m_next = next; updatePrefetchTarget(); } +#else void setNextSibling(Node* next) { m_next = next; } +#endif + void updatePreviousNode() { m_previousNode = traversePreviousNode(); if (m_previousNode) m_previousNode->setNextNode(this); } + void updateNextNode() { m_nextNode = traverseNextNode(); if (m_nextNode) m_nextNode->setPreviousNode(this); } + void updatePrevNextNodesInSubtree(); + + void setPreviousNode(Node* previous) { m_previousNode = previous; } + void setNextNode(Node* next) { m_nextNode = next; } // FIXME: These two functions belong in editing -- "atomic node" is an editing concept. Node* previousNodeConsideringAtomicNodes() const; @@ -314,6 +341,9 @@ public: void setIsLink() { setFlag(IsLinkFlag); } void clearIsLink() { clearFlag(IsLinkFlag); } + void setIeForbidsInsertHTML() { setFlag(IeForbidsInsertHTML); } + bool ieForbidsInsertHTML() const { return getFlag(IeForbidsInsertHTML); } + enum ShouldSetAttached { SetAttached, DoNotSetAttached @@ -392,12 +422,27 @@ public: // This can be used to restrict traversal to a particular sub-tree. Node* traverseNextNode(const Node* stayWithin = 0) const; + Node* traverseNextNodeFastPath() const { prefetchTarget(); return m_nextNode; } + + ALWAYS_INLINE void prefetchTarget() const { +#ifdef __ARM_USE_PLD + if (m_prefetch) { + __builtin_prefetch(((char *) m_prefetch)); + __builtin_prefetch(((char *) m_prefetch) + 64); + } +#endif + } + + Node* lastDescendantNode(bool includeThis = false) const; + // Like traverseNextNode, but skips children and starts with the next sibling. Node* traverseNextSibling(const Node* stayWithin = 0) const; // Does a reverse pre-order traversal to find the node that comes before the current one in document order Node* traversePreviousNode(const Node* stayWithin = 0) const; + Node* traversePreviousNodeFastPath() const { return m_previousNode; } + // Like traverseNextNode, but visits parents after their children. Node* traverseNextNodePostOrder() const; @@ -515,9 +560,10 @@ public: void notifyLocalNodeListsLabelChanged(); void removeCachedClassNodeList(ClassNodeList*, const String&); void removeCachedNameNodeList(NameNodeList*, const String&); - void removeCachedTagNodeList(TagNodeList*, const QualifiedName&); + void removeCachedTagNodeList(TagNodeList*, const AtomicString&); + void removeCachedTagNodeListNS(TagNodeListNS*, const QualifiedName&); void removeCachedLabelsNodeList(DynamicNodeList*); - + PassRefPtr<NodeList> getElementsByTagName(const AtomicString&); PassRefPtr<NodeList> getElementsByTagNameNS(const AtomicString& namespaceURI, const AtomicString& localName); PassRefPtr<NodeList> getElementsByName(const String& elementName); @@ -593,7 +639,7 @@ private: InActiveChainFlag = 1 << 15, InDetachFlag = 1 << 16, HasRareDataFlag = 1 << 17, - IsShadowRootFlag = 1 << 18, + IsShadowRootOrSVGShadowRootFlag = 1 << 18, // These bits are used by derived classes, pulled up here so they can // be stored in the same memory word as the Node bits above. @@ -605,11 +651,14 @@ private: IsSynchronizingSVGAttributesFlag = 1 << 23, // SVGElement HasSVGRareDataFlag = 1 << 24, // SVGElement #endif - StyleChangeMask = 1 << nodeStyleChangeShift | 1 << (nodeStyleChangeShift + 1), SelfOrAncestorHasDirAutoFlag = 1 << 27, + IeForbidsInsertHTML = 1 << 28, + + NodeDetachClearFlags = IsActiveFlag | IsHoveredFlag | InActiveChainFlag | IsAttachedFlag | InDetachFlag, + #if ENABLE(SVG) DefaultNodeFlags = IsParsingChildrenFinishedFlag | IsStyleAttributeValidFlag | AreSVGAttributesValidFlag #else @@ -619,7 +668,7 @@ private: // 4 bits remaining - bool getFlag(NodeFlags mask) const { return m_nodeFlags & mask; } + ALWAYS_INLINE bool getFlag(NodeFlags mask) const { return m_nodeFlags & mask; } void setFlag(bool f, NodeFlags mask) const { m_nodeFlags = (m_nodeFlags & ~mask) | (-(int32_t)f & mask); } void setFlag(NodeFlags mask) const { m_nodeFlags |= mask; } void clearFlag(NodeFlags mask) const { m_nodeFlags &= ~mask; } @@ -631,9 +680,11 @@ protected: CreateComment = DefaultNodeFlags | IsCommentFlag, CreateContainer = DefaultNodeFlags | IsContainerFlag, CreateElement = CreateContainer | IsElementFlag, + CreateShadowRoot = CreateContainer | IsShadowRootOrSVGShadowRootFlag, CreateStyledElement = CreateElement | IsStyledElementFlag, CreateHTMLElement = CreateStyledElement | IsHTMLFlag, CreateSVGElement = CreateStyledElement | IsSVGFlag, + CreateSVGShadowRoot = CreateSVGElement | IsShadowRootOrSVGShadowRootFlag, }; Node(Document*, ConstructionType); @@ -690,8 +741,13 @@ private: Document* m_document; Node* m_previous; Node* m_next; +#ifdef __ARM_USE_PLD + Node* m_prefetch; +#endif RenderObject* m_renderer; mutable uint32_t m_nodeFlags; + Node* m_previousNode; + Node* m_nextNode; protected: bool isParsingChildrenFinished() const { return getFlag(IsParsingChildrenFinishedFlag); } @@ -728,7 +784,7 @@ inline void addSubresourceURL(ListHashSet<KURL>& urls, const KURL& url) inline ContainerNode* Node::parentNode() const { - return getFlag(IsShadowRootFlag) || isSVGShadowRoot() ? 0 : parent(); + return getFlag(IsShadowRootOrSVGShadowRootFlag) ? 0 : parent(); } inline ContainerNode* Node::parentOrHostNode() const @@ -738,7 +794,7 @@ inline ContainerNode* Node::parentOrHostNode() const inline ContainerNode* Node::parentNodeGuaranteedHostFree() const { - ASSERT(!getFlag(IsShadowRootFlag) && !isSVGShadowRoot()); + ASSERT(!getFlag(IsShadowRootOrSVGShadowRootFlag)); return parentOrHostNode(); } diff --git a/Source/WebCore/dom/NodeRareData.h b/Source/WebCore/dom/NodeRareData.h index ac05d3e..7bbd0c1 100644 --- a/Source/WebCore/dom/NodeRareData.h +++ b/Source/WebCore/dom/NodeRareData.h @@ -49,10 +49,13 @@ public: typedef HashMap<String, NameNodeList*> NameNodeListCache; NameNodeListCache m_nameNodeListCache; - - typedef HashMap<RefPtr<QualifiedName::QualifiedNameImpl>, TagNodeList*> TagNodeListCache; + + typedef HashMap<AtomicStringImpl*, TagNodeList*> TagNodeListCache; TagNodeListCache m_tagNodeListCache; + typedef HashMap<RefPtr<QualifiedName::QualifiedNameImpl>, TagNodeListNS*> TagNodeListCacheNS; + TagNodeListCacheNS m_tagNodeListCacheNS; + RefPtr<DynamicNodeList> m_labelsNodeListCache; static PassOwnPtr<NodeListsNodeData> create() @@ -106,6 +109,15 @@ public: void clearNodeLists() { m_nodeLists.clear(); } void setNodeLists(PassOwnPtr<NodeListsNodeData> lists) { m_nodeLists = lists; } NodeListsNodeData* nodeLists() const { return m_nodeLists.get(); } + NodeListsNodeData* ensureNodeLists(Node* n) + { + if (!m_nodeLists) { + m_nodeLists = NodeListsNodeData::create(); + if (n->document()) + n->document()->addNodeListCache(); + } + return m_nodeLists.get(); + } short tabIndex() const { return m_tabIndex; } void setTabIndexExplicitly(short index) { m_tabIndex = index; m_tabIndexWasSetExplicitly = true; } diff --git a/Source/WebCore/dom/ProcessingInstruction.cpp b/Source/WebCore/dom/ProcessingInstruction.cpp index 30111d8..3feb0ab 100644 --- a/Source/WebCore/dom/ProcessingInstruction.cpp +++ b/Source/WebCore/dom/ProcessingInstruction.cpp @@ -161,9 +161,10 @@ void ProcessingInstruction::checkStyleSheet() m_loading = true; document()->addPendingSheet(); + ResourceRequest request(document()->completeURL(href)); #if ENABLE(XSLT) if (m_isXSL) - m_cachedSheet = document()->cachedResourceLoader()->requestXSLStyleSheet(url); + m_cachedSheet = document()->cachedResourceLoader()->requestXSLStyleSheet(request); else #endif { @@ -171,7 +172,7 @@ void ProcessingInstruction::checkStyleSheet() if (charset.isEmpty()) charset = document()->charset(); - m_cachedSheet = document()->cachedResourceLoader()->requestCSSStyleSheet(url, charset); + m_cachedSheet = document()->cachedResourceLoader()->requestCSSStyleSheet(request, charset); } if (m_cachedSheet) m_cachedSheet->addClient(this); diff --git a/Source/WebCore/dom/RequestAnimationFrameCallback.h b/Source/WebCore/dom/RequestAnimationFrameCallback.h index 3edeb9e..a867922 100644 --- a/Source/WebCore/dom/RequestAnimationFrameCallback.h +++ b/Source/WebCore/dom/RequestAnimationFrameCallback.h @@ -31,8 +31,7 @@ #ifndef RequestAnimationFrameCallback_h #define RequestAnimationFrameCallback_h -#include "Element.h" -#include <wtf/PassRefPtr.h> +#include "DOMTimeStamp.h" #include <wtf/RefCounted.h> namespace WebCore { @@ -42,7 +41,6 @@ public: virtual ~RequestAnimationFrameCallback() { } virtual bool handleEvent(DOMTimeStamp) = 0; - RefPtr<Element> m_element; int m_id; bool m_firedOrCancelled; }; diff --git a/Source/WebCore/dom/ScriptElement.cpp b/Source/WebCore/dom/ScriptElement.cpp index 55a7949..dc075ae 100644 --- a/Source/WebCore/dom/ScriptElement.cpp +++ b/Source/WebCore/dom/ScriptElement.cpp @@ -248,7 +248,8 @@ bool ScriptElement::requestScript(const String& sourceUrl) ASSERT(!m_cachedScript); // FIXME: If sourceUrl is empty, we should dispatchErrorEvent(). - m_cachedScript = m_element->document()->cachedResourceLoader()->requestScript(sourceUrl, scriptCharset()); + ResourceRequest request(m_element->document()->completeURL(sourceUrl)); + m_cachedScript = m_element->document()->cachedResourceLoader()->requestScript(request, scriptCharset()); m_isExternalScript = true; if (m_cachedScript) diff --git a/Source/WebCore/dom/ScriptedAnimationController.cpp b/Source/WebCore/dom/ScriptedAnimationController.cpp index 0c70359..4fbf6d9 100644 --- a/Source/WebCore/dom/ScriptedAnimationController.cpp +++ b/Source/WebCore/dom/ScriptedAnimationController.cpp @@ -29,16 +29,29 @@ #if ENABLE(REQUEST_ANIMATION_FRAME) #include "Document.h" -#include "Element.h" #include "FrameView.h" #include "RequestAnimationFrameCallback.h" +#if USE(REQUEST_ANIMATION_FRAME_TIMER) +#include <algorithm> +#include <wtf/CurrentTime.h> + +using namespace std; + +// Allow a little more than 60fps to make sure we can at least hit that frame rate. +#define MinimumAnimationInterval 0.015 +#endif + namespace WebCore { ScriptedAnimationController::ScriptedAnimationController(Document* document) : m_document(document) , m_nextCallbackId(0) , m_suspendCount(0) +#if USE(REQUEST_ANIMATION_FRAME_TIMER) + , m_animationTimer(this, &ScriptedAnimationController::animationTimerFired) + , m_lastAnimationFrameTime(0) +#endif { } @@ -51,20 +64,17 @@ void ScriptedAnimationController::resume() { --m_suspendCount; if (!m_suspendCount && m_callbacks.size()) - if (FrameView* fv = m_document->view()) - fv->scheduleAnimation(); + scheduleAnimation(); } -ScriptedAnimationController::CallbackId ScriptedAnimationController::registerCallback(PassRefPtr<RequestAnimationFrameCallback> callback, Element* animationElement) +ScriptedAnimationController::CallbackId ScriptedAnimationController::registerCallback(PassRefPtr<RequestAnimationFrameCallback> callback) { ScriptedAnimationController::CallbackId id = m_nextCallbackId++; callback->m_firedOrCancelled = false; callback->m_id = id; - callback->m_element = animationElement; m_callbacks.append(callback); if (!m_suspendCount) - if (FrameView* view = m_document->view()) - view->scheduleAnimation(); + scheduleAnimation(); return id; } @@ -83,37 +93,19 @@ void ScriptedAnimationController::serviceScriptedAnimations(DOMTimeStamp time) { if (!m_callbacks.size() || m_suspendCount) return; - // We want to run the callback for all elements in the document that have registered - // for a callback and that are visible. Running the callbacks can cause new callbacks - // to be registered, existing callbacks to be cancelled, and elements to gain or lose - // visibility so this code has to iterate carefully. - - // FIXME: Currently, this code doesn't do any visibility tests beyond checking display: // First, generate a list of callbacks to consider. Callbacks registered from this point // on are considered only for the "next" frame, not this one. CallbackList callbacks(m_callbacks); - // Firing the callback may cause the visibility of other elements to change. To avoid - // missing any callbacks, we keep iterating through the list of candiate callbacks and firing - // them until nothing new becomes visible. - bool firedCallback; - do { - firedCallback = false; - // A previous iteration may have invalidated style (or layout). Update styles for each iteration - // for now since all we check is the existence of a renderer. - m_document->updateStyleIfNeeded(); - for (size_t i = 0; i < callbacks.size(); ++i) { - RequestAnimationFrameCallback* callback = callbacks[i].get(); - if (!callback->m_firedOrCancelled && (!callback->m_element || callback->m_element->renderer())) { - callback->m_firedOrCancelled = true; - callback->handleEvent(time); - firedCallback = true; - callbacks.remove(i); - break; - } + for (size_t i = 0; i < callbacks.size(); ++i) { + RequestAnimationFrameCallback* callback = callbacks[i].get(); + if (!callback->m_firedOrCancelled) { + callback->m_firedOrCancelled = true; + callback->handleEvent(time); } - } while (firedCallback); + } + m_document->updateStyleIfNeeded(); // Remove any callbacks we fired from the list of pending callbacks. for (size_t i = 0; i < m_callbacks.size();) { @@ -124,10 +116,28 @@ void ScriptedAnimationController::serviceScriptedAnimations(DOMTimeStamp time) } if (m_callbacks.size()) - if (FrameView* view = m_document->view()) - view->scheduleAnimation(); + scheduleAnimation(); } +void ScriptedAnimationController::scheduleAnimation() +{ +#if USE(REQUEST_ANIMATION_FRAME_TIMER) + double scheduleDelay = max<double>(MinimumAnimationInterval - (currentTime() - m_lastAnimationFrameTime), 0); + m_animationTimer.startOneShot(scheduleDelay); +#else + if (FrameView* frameView = m_document->view()) + frameView->scheduleAnimation(); +#endif +} + +#if USE(REQUEST_ANIMATION_FRAME_TIMER) +void ScriptedAnimationController::animationTimerFired(Timer<ScriptedAnimationController>*) +{ + m_lastAnimationFrameTime = currentTime(); + serviceScriptedAnimations(convertSecondsToDOMTimeStamp(m_lastAnimationFrameTime)); +} +#endif + } #endif diff --git a/Source/WebCore/dom/ScriptedAnimationController.h b/Source/WebCore/dom/ScriptedAnimationController.h index 7141968..f6f06a9 100644 --- a/Source/WebCore/dom/ScriptedAnimationController.h +++ b/Source/WebCore/dom/ScriptedAnimationController.h @@ -28,6 +28,9 @@ #if ENABLE(REQUEST_ANIMATION_FRAME) #include "DOMTimeStamp.h" +#if USE(REQUEST_ANIMATION_FRAME_TIMER) +#include "Timer.h" +#endif #include <wtf/Noncopyable.h> #include <wtf/PassOwnPtr.h> #include <wtf/RefPtr.h> @@ -36,7 +39,6 @@ namespace WebCore { class Document; -class Element; class RequestAnimationFrameCallback; class ScriptedAnimationController { @@ -49,7 +51,7 @@ public: typedef int CallbackId; - CallbackId registerCallback(PassRefPtr<RequestAnimationFrameCallback>, Element*); + CallbackId registerCallback(PassRefPtr<RequestAnimationFrameCallback>); void cancelCallback(CallbackId); void serviceScriptedAnimations(DOMTimeStamp); @@ -58,12 +60,21 @@ public: private: explicit ScriptedAnimationController(Document*); + typedef Vector<RefPtr<RequestAnimationFrameCallback> > CallbackList; CallbackList m_callbacks; Document* m_document; CallbackId m_nextCallbackId; int m_suspendCount; + + void scheduleAnimation(); + +#if USE(REQUEST_ANIMATION_FRAME_TIMER) + void animationTimerFired(Timer<ScriptedAnimationController>*); + Timer<ScriptedAnimationController> m_animationTimer; + double m_lastAnimationFrameTime; +#endif }; } diff --git a/Source/WebCore/dom/SelectorNodeList.cpp b/Source/WebCore/dom/SelectorNodeList.cpp index 7611488..82f1103 100644 --- a/Source/WebCore/dom/SelectorNodeList.cpp +++ b/Source/WebCore/dom/SelectorNodeList.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2012 The Linux Foundation All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -55,16 +56,25 @@ PassRefPtr<StaticNodeList> createSelectorNodeList(Node* rootNode, const CSSSelec if (element && (rootNode->isDocumentNode() || element->isDescendantOf(rootNode)) && selectorChecker.checkSelector(onlySelector, element)) nodes.append(element); } else { - for (Node* n = rootNode->firstChild(); n; n = n->traverseNextNode(rootNode)) { + Vector<CSSSelector*> querySelectors; + querySelectors.reserveInitialCapacity(16); + for (CSSSelector* selector = querySelectorList.first(); selector; selector = CSSSelectorList::next(selector)) + querySelectors.append(selector); + int querySelectorsCount = querySelectors.size(); + + Node* lastNode = rootNode->lastDescendantNode(); + for (Node* n = rootNode->firstChild(); n; n = n->traverseNextNodeFastPath()) { if (n->isElementNode()) { Element* element = static_cast<Element*>(n); - for (CSSSelector* selector = querySelectorList.first(); selector; selector = CSSSelectorList::next(selector)) { - if (selectorChecker.checkSelector(selector, element)) { + for (int i = 0; i < querySelectorsCount; i++) { + if (selectorChecker.checkSelector(querySelectors[i], element)) { nodes.append(n); break; } } } + if (n == lastNode) + break; } } diff --git a/Source/WebCore/dom/TagNodeList.cpp b/Source/WebCore/dom/TagNodeList.cpp index 4914e09..df51fe1 100644 --- a/Source/WebCore/dom/TagNodeList.cpp +++ b/Source/WebCore/dom/TagNodeList.cpp @@ -4,6 +4,7 @@ * (C) 2001 Dirk Mueller (mueller@kde.org) * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2012 The Linux Foundation 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 @@ -29,25 +30,45 @@ namespace WebCore { -TagNodeList::TagNodeList(PassRefPtr<Node> rootNode, const AtomicString& namespaceURI, const AtomicString& localName) +TagNodeListNS::TagNodeListNS(PassRefPtr<Node> rootNode, const AtomicString& namespaceURI, const AtomicString& localName) : DynamicNodeList(rootNode) , m_namespaceURI(namespaceURI) , m_localName(localName) + , m_isStarAtomNamespaceURI(m_namespaceURI == starAtom) + , m_isStarAtomlocalName(m_localName == starAtom) { ASSERT(m_namespaceURI.isNull() || !m_namespaceURI.isEmpty()); } -TagNodeList::~TagNodeList() +TagNodeListNS::~TagNodeListNS() { - m_rootNode->removeCachedTagNodeList(this, QualifiedName(nullAtom, m_localName, m_namespaceURI)); -} + m_rootNode->removeCachedTagNodeListNS(this, QualifiedName(nullAtom, m_localName, m_namespaceURI)); +} -bool TagNodeList::nodeMatches(Element* testNode) const +bool TagNodeListNS::nodeMatches(Element* testNode) const { - if (m_namespaceURI != starAtom && m_namespaceURI != testNode->namespaceURI()) + if (!m_isStarAtomNamespaceURI && m_namespaceURI != testNode->namespaceURI()) return false; - return m_localName == starAtom || m_localName == testNode->localName(); + return m_isStarAtomlocalName || m_localName == testNode->localName(); } +TagNodeList::TagNodeList(PassRefPtr<Node> rootNode, const AtomicString& localName) + : DynamicNodeList(rootNode) + , m_localName(localName) + , m_isStarAtomlocalName(m_localName == starAtom) +{ +} + +TagNodeList::~TagNodeList() +{ + m_rootNode->removeCachedTagNodeList(this, m_localName); +} + +bool TagNodeList::nodeMatches(Element* testNode) const +{ + return m_isStarAtomlocalName || m_localName == testNode->localName(); +} + + } // namespace WebCore diff --git a/Source/WebCore/dom/TagNodeList.h b/Source/WebCore/dom/TagNodeList.h index 9053b53..f255532 100644 --- a/Source/WebCore/dom/TagNodeList.h +++ b/Source/WebCore/dom/TagNodeList.h @@ -29,24 +29,45 @@ namespace WebCore { - // NodeList that limits to a particular tag. - class TagNodeList : public DynamicNodeList { - public: - static PassRefPtr<TagNodeList> create(PassRefPtr<Node> rootNode, const AtomicString& namespaceURI, const AtomicString& localName) - { - return adoptRef(new TagNodeList(rootNode, namespaceURI, localName)); - } +// NodeList with namespace that limits to a particular tag. +class TagNodeListNS : public DynamicNodeList { +public: + static PassRefPtr<TagNodeListNS> create(PassRefPtr<Node> rootNode, const AtomicString& namespaceURI, const AtomicString& localName) + { + return adoptRef(new TagNodeListNS(rootNode, namespaceURI, localName)); + } - virtual ~TagNodeList(); + virtual ~TagNodeListNS(); - private: - TagNodeList(PassRefPtr<Node> rootNode, const AtomicString& namespaceURI, const AtomicString& localName); +private: + TagNodeListNS(PassRefPtr<Node> rootNode, const AtomicString& namespaceURI, const AtomicString& localName); - virtual bool nodeMatches(Element*) const; + virtual bool nodeMatches(Element*) const; - AtomicString m_namespaceURI; - AtomicString m_localName; - }; + AtomicString m_namespaceURI; + AtomicString m_localName; + bool m_isStarAtomNamespaceURI : 1; + bool m_isStarAtomlocalName : 1; +}; + +// NodeList that limits to a particular tag. +class TagNodeList : public DynamicNodeList { +public: + static PassRefPtr<TagNodeList> create(PassRefPtr<Node> rootNode, const AtomicString& localName) + { + return adoptRef(new TagNodeList(rootNode, localName)); + } + + virtual ~TagNodeList(); + +private: + TagNodeList(PassRefPtr<Node> rootNode, const AtomicString& localName); + + virtual bool nodeMatches(Element*) const; + + AtomicString m_localName; + bool m_isStarAtomlocalName; +}; } // namespace WebCore diff --git a/Source/WebCore/dom/Text.cpp b/Source/WebCore/dom/Text.cpp index c4ea0a6..01a454d 100644 --- a/Source/WebCore/dom/Text.cpp +++ b/Source/WebCore/dom/Text.cpp @@ -213,7 +213,7 @@ bool Text::rendererIsNeeded(RenderStyle *style) if (style->preserveNewline()) // pre/pre-wrap/pre-line always make renderers. return true; - RenderObject *prev = previousRenderer(); + RenderObject* prev = m_previousRenderer ? m_previousRenderer : previousRenderer(); if (prev && prev->isBR()) // <span><br/> <br/></span> return false; diff --git a/Source/WebCore/dom/Text.h b/Source/WebCore/dom/Text.h index 5995f1f..4db3bb3 100644 --- a/Source/WebCore/dom/Text.h +++ b/Source/WebCore/dom/Text.h @@ -43,9 +43,12 @@ public: virtual void attach(); + void setPreviousRenderer(RenderObject* renderer) { m_previousRenderer = renderer; } + protected: Text(Document* document, const String& data) : CharacterData(document, data, CreateText) + , m_previousRenderer(0) { } @@ -63,6 +66,8 @@ private: #ifndef NDEBUG virtual void formatForDebugger(char* buffer, unsigned length) const; #endif + + RenderObject* m_previousRenderer; }; } // namespace WebCore diff --git a/Source/WebCore/dom/TreeScope.cpp b/Source/WebCore/dom/TreeScope.cpp index a995a2d..45c7a8f 100644 --- a/Source/WebCore/dom/TreeScope.cpp +++ b/Source/WebCore/dom/TreeScope.cpp @@ -97,7 +97,7 @@ Element* TreeScope::getElementByAccessKey(const String& key) const if (key.isEmpty()) return 0; if (!m_accessKeyMapValid) { - for (Node* n = firstChild(); n; n = n->traverseNextNode()) { + for (Node* n = firstChild(); n; n = n->traverseNextNodeFastPath()) { if (!n->isElementNode()) continue; Element* element = static_cast<Element*>(n); @@ -149,7 +149,7 @@ Element* TreeScope::findAnchor(const String& name) return 0; if (Element* element = getElementById(name)) return element; - for (Node* node = this; node; node = node->traverseNextNode()) { + for (Node* node = this; node; node = node->traverseNextNodeFastPath()) { if (node->hasTagName(aTag)) { HTMLAnchorElement* anchor = static_cast<HTMLAnchorElement*>(node); if (document()->inQuirksMode()) { |