https://bugs.webkit.org/show_bug.cgi?id=91277
Reviewed by Ojan Vafai.
Explicitely check the invalidation type and the changed attribute in NodeListNodeData::invalidateCaches
and ElementRareData::clearHTMLCollectionCaches to only invalidate node lists affected by the change.
Also merged invalidateNodeListsCacheAfterAttributeChanged and invalidateNodeListsCacheAfterChildrenChanged
as invalidateNodeListCachesInAncestors since they're almost identical after r122498.
In addition, moved shouldInvalidateNodeListForType from Document.cpp to DynamicNodeList.h and renamed it to
shouldInvalidateTypeOnAttributeChange since it needs to called in Node.cpp and ElementRareData.h.
* dom/Attr.cpp:
(WebCore::Attr::setValue):
(WebCore::Attr::childrenChanged):
* dom/ContainerNode.cpp:
(WebCore::ContainerNode::childrenChanged):
* dom/Document.cpp:
(WebCore::Document::registerNodeListCache): Calls isRootedAtDocument() instead of directly comparing
the value of NodeListRootType in order to prepare for the bug 80269.
(WebCore::Document::unregisterNodeListCache): Ditto.
(WebCore): shouldInvalidateNodeListForType is moved to DynamicNodeList.h
(WebCore::Document::shouldInvalidateNodeListCaches):
* dom/DynamicNodeList.h:
(DynamicNodeListCacheBase):
(WebCore::DynamicNodeListCacheBase::shouldInvalidateTypeOnAttributeChange): Moved from Document.cpp.
* dom/Element.cpp:
(WebCore::Element::attributeChanged):
* dom/ElementRareData.h:
(WebCore::ElementRareData::clearHTMLCollectionCaches): Takes const QualifiedName* to compare against
the invalidation type of HTML collections via shouldInvalidateTypeOnAttributeChange.
* dom/Node.cpp:
(WebCore::Node::invalidateNodeListCachesInAncestors): Merged invalidateNodeListCachesInAncestors and
invalidateNodeListsCacheAfterChildrenChanged. Also pass attrName to clearHTMLCollectionCaches.
(WebCore::NodeListsNodeData::invalidateCaches): Compares attrName against the invalidation type of
node lists via shouldInvalidateTypeOnAttributeChange.
(WebCore):
* dom/Node.h:
(Node):
* dom/NodeRareData.h:
(WebCore::NodeRareData::ensureNodeLists): Merged NodeRareData::createNodeLists.
(WebCore::NodeRareData::clearChildNodeListCache): Moved from Node.cpp.
(NodeRareData):
* html/HTMLCollection.h:
(HTMLCollectionCacheBase):
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@122637
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2012-07-13 Ryosuke Niwa <rniwa@webkit.org>
+
+ NodeLists should not invalidate on irreleavnt attribute changes
+ https://bugs.webkit.org/show_bug.cgi?id=91277
+
+ Reviewed by Ojan Vafai.
+
+ Explicitely check the invalidation type and the changed attribute in NodeListNodeData::invalidateCaches
+ and ElementRareData::clearHTMLCollectionCaches to only invalidate node lists affected by the change.
+
+ Also merged invalidateNodeListsCacheAfterAttributeChanged and invalidateNodeListsCacheAfterChildrenChanged
+ as invalidateNodeListCachesInAncestors since they're almost identical after r122498.
+
+ In addition, moved shouldInvalidateNodeListForType from Document.cpp to DynamicNodeList.h and renamed it to
+ shouldInvalidateTypeOnAttributeChange since it needs to called in Node.cpp and ElementRareData.h.
+
+ * dom/Attr.cpp:
+ (WebCore::Attr::setValue):
+ (WebCore::Attr::childrenChanged):
+ * dom/ContainerNode.cpp:
+ (WebCore::ContainerNode::childrenChanged):
+ * dom/Document.cpp:
+ (WebCore::Document::registerNodeListCache): Calls isRootedAtDocument() instead of directly comparing
+ the value of NodeListRootType in order to prepare for the bug 80269.
+ (WebCore::Document::unregisterNodeListCache): Ditto.
+ (WebCore): shouldInvalidateNodeListForType is moved to DynamicNodeList.h
+ (WebCore::Document::shouldInvalidateNodeListCaches):
+ * dom/DynamicNodeList.h:
+ (DynamicNodeListCacheBase):
+ (WebCore::DynamicNodeListCacheBase::shouldInvalidateTypeOnAttributeChange): Moved from Document.cpp.
+ * dom/Element.cpp:
+ (WebCore::Element::attributeChanged):
+ * dom/ElementRareData.h:
+ (WebCore::ElementRareData::clearHTMLCollectionCaches): Takes const QualifiedName* to compare against
+ the invalidation type of HTML collections via shouldInvalidateTypeOnAttributeChange.
+ * dom/Node.cpp:
+ (WebCore::Node::invalidateNodeListCachesInAncestors): Merged invalidateNodeListCachesInAncestors and
+ invalidateNodeListsCacheAfterChildrenChanged. Also pass attrName to clearHTMLCollectionCaches.
+ (WebCore::NodeListsNodeData::invalidateCaches): Compares attrName against the invalidation type of
+ node lists via shouldInvalidateTypeOnAttributeChange.
+ (WebCore):
+ * dom/Node.h:
+ (Node):
+ * dom/NodeRareData.h:
+ (WebCore::NodeRareData::ensureNodeLists): Merged NodeRareData::createNodeLists.
+ (WebCore::NodeRareData::clearChildNodeListCache): Moved from Node.cpp.
+ (NodeRareData):
+ * html/HTMLCollection.h:
+ (HTMLCollectionCacheBase):
+
2012-07-13 Arpita Bahuguna <arpitabahuguna@gmail.com>
Refactor RenderTable to use the section's iteration functions.
createTextChild();
m_ignoreChildrenChanged--;
- invalidateNodeListsCacheAfterAttributeChanged(m_name, m_element);
+ invalidateNodeListCachesInAncestors(&m_name, m_element);
}
void Attr::setValue(const AtomicString& value, ExceptionCode&)
if (m_ignoreChildrenChanged > 0)
return;
- invalidateNodeListsCacheAfterAttributeChanged(qualifiedName(), m_element);
+ invalidateNodeListCachesInAncestors(&qualifiedName(), m_element);
// FIXME: We should include entity references in the value
document()->incDOMTreeVersion();
if (!changedByParser && childCountDelta)
document()->updateRangesAfterChildrenChanged(this);
- invalidateNodeListsCacheAfterChildrenChanged();
+ invalidateNodeListCachesInAncestors();
}
void ContainerNode::cloneChildNodes(ContainerNode *clone)
if (list->type() != InvalidCollectionType)
m_nodeListCounts[InvalidateOnIdNameAttrChange]++;
m_nodeListCounts[list->invalidationType()]++;
- if (list->rootType() == NodeListIsRootedAtDocument)
+ if (list->isRootedAtDocument())
m_listsInvalidatedAtDocument.add(list);
}
if (list->type() != InvalidCollectionType)
m_nodeListCounts[InvalidateOnIdNameAttrChange]--;
m_nodeListCounts[list->invalidationType()]--;
- if (list->rootType() == NodeListIsRootedAtDocument) {
+ if (list->isRootedAtDocument()) {
ASSERT(m_listsInvalidatedAtDocument.contains(list));
m_listsInvalidatedAtDocument.remove(list);
}
}
-static ALWAYS_INLINE bool shouldInvalidateNodeListForType(NodeListInvalidationType type, const QualifiedName& attrName)
-{
- switch (type) {
- case InvalidateOnClassAttrChange:
- return attrName == classAttr;
- case InvalidateOnNameAttrChange:
- return attrName == nameAttr;
- case InvalidateOnIdNameAttrChange:
- return attrName == idAttr || attrName == nameAttr;
- case InvalidateOnForAttrChange:
- return attrName == forAttr;
- case InvalidateForFormControls:
- return attrName == nameAttr || attrName == idAttr || attrName == forAttr || attrName == typeAttr;
- case InvalidateOnHRefAttrChange:
- return attrName == hrefAttr;
- case InvalidateOnItemAttrChange:
-#if ENABLE(MICRODATA)
- return attrName == itemscopeAttr || attrName == itempropAttr || attrName == itemtypeAttr;
-#endif // Intentionally fall through
- case DoNotInvalidateOnAttributeChanges:
- ASSERT_NOT_REACHED();
- return false;
- case InvalidateOnAnyAttrChange:
- return true;
- }
- return false;
-}
-
bool Document::shouldInvalidateNodeListCaches(const QualifiedName* attrName) const
{
if (attrName) {
for (int type = DoNotInvalidateOnAttributeChanges + 1; type < numNodeListInvalidationTypes; type++) {
- if (m_nodeListCounts[type] && shouldInvalidateNodeListForType(static_cast<NodeListInvalidationType>(type), *attrName))
+ if (m_nodeListCounts[type] && DynamicNodeListCacheBase::shouldInvalidateTypeOnAttributeChange(static_cast<NodeListInvalidationType>(type), *attrName))
return true;
}
return false;
#include "CollectionType.h"
#include "Document.h"
+#include "HTMLNames.h"
#include "NodeList.h"
#include <wtf/Forward.h>
#include <wtf/RefPtr.h>
public:
ALWAYS_INLINE bool isRootedAtDocument() const { return m_rootedAtDocument; }
- ALWAYS_INLINE bool shouldInvalidateOnAttributeChange() const { return m_invalidationType != DoNotInvalidateOnAttributeChanges; }
- ALWAYS_INLINE NodeListRootType rootType() { return m_rootedAtDocument ? NodeListIsRootedAtDocument : NodeListIsRootedAtNode; }
ALWAYS_INLINE NodeListInvalidationType invalidationType() const { return static_cast<NodeListInvalidationType>(m_invalidationType); }
ALWAYS_INLINE CollectionType type() const { return static_cast<CollectionType>(m_collectionType); }
void invalidateCache() const;
+ static bool shouldInvalidateTypeOnAttributeChange(NodeListInvalidationType, const QualifiedName&);
+
protected:
ALWAYS_INLINE bool isItemCacheValid() const { return m_isItemCacheValid; }
ALWAYS_INLINE Node* cachedItem() const { return m_cachedItem; }
const unsigned m_collectionType : 5;
};
+ALWAYS_INLINE bool DynamicNodeListCacheBase::shouldInvalidateTypeOnAttributeChange(NodeListInvalidationType type, const QualifiedName& attrName)
+{
+ switch (type) {
+ case InvalidateOnClassAttrChange:
+ return attrName == HTMLNames::classAttr;
+ case InvalidateOnNameAttrChange:
+ return attrName == HTMLNames::nameAttr;
+ case InvalidateOnIdNameAttrChange:
+ return attrName == HTMLNames::idAttr || attrName == HTMLNames::nameAttr;
+ case InvalidateOnForAttrChange:
+ return attrName == HTMLNames::forAttr;
+ case InvalidateForFormControls:
+ return attrName == HTMLNames::nameAttr || attrName == HTMLNames::idAttr || attrName == HTMLNames::forAttr || attrName == HTMLNames::typeAttr;
+ case InvalidateOnHRefAttrChange:
+ return attrName == HTMLNames::hrefAttr;
+ case InvalidateOnItemAttrChange:
+#if ENABLE(MICRODATA)
+ return attrName == HTMLNames::itemscopeAttr || attrName == HTMLNames::itempropAttr || attrName == HTMLNames::itemtypeAttr;
+#endif // Intentionally fall through
+ case DoNotInvalidateOnAttributeChanges:
+ ASSERT_NOT_REACHED();
+ return false;
+ case InvalidateOnAnyAttrChange:
+ return true;
+ }
+ return false;
+}
+
class DynamicNodeList : public NodeList, public DynamicNodeListCacheBase {
public:
enum NodeListType {
setNeedsStyleRecalc();
}
- invalidateNodeListsCacheAfterAttributeChanged(attribute.name(), this);
+ invalidateNodeListCachesInAncestors(&attribute.name(), this);
if (!AXObjectCache::accessibilityEnabled())
return;
(*m_cachedCollections)[type - FirstNodeCollectionType] = 0;
}
- void clearHTMLCollectionCaches()
+ void clearHTMLCollectionCaches(const QualifiedName* attrName)
{
if (!m_cachedCollections)
return;
+ bool shouldIgnoreType = !attrName || *attrName == HTMLNames::idAttr || *attrName == HTMLNames::nameAttr;
+
for (unsigned i = 0; i < (*m_cachedCollections).size(); i++) {
- if ((*m_cachedCollections)[i])
- (*m_cachedCollections)[i]->invalidateCache();
+ if (HTMLCollection* collection = (*m_cachedCollections)[i]) {
+ if (shouldIgnoreType || DynamicNodeListCacheBase::shouldInvalidateTypeOnAttributeChange(collection->invalidationType(), *attrName))
+ collection->invalidateCache();
+ }
}
}
return count;
}
-void Node::invalidateNodeListsCacheAfterAttributeChanged(const QualifiedName& attrName, Element* attributeOwnerElement)
+void Node::invalidateNodeListCachesInAncestors(const QualifiedName* attrName, Element* attributeOwnerElement)
{
- if (hasRareData() && isAttributeNode()) {
- NodeRareData* data = rareData();
- ASSERT(!data->nodeLists());
- data->clearChildNodeListCache();
- }
+ if (hasRareData() && (!attrName || isAttributeNode()))
+ rareData()->clearChildNodeListCache();
// Modifications to attributes that are not associated with an Element can't invalidate NodeList caches.
- if (!attributeOwnerElement)
- return;
-
- if (!document()->shouldInvalidateNodeListCaches(&attrName))
+ if (attrName && !attributeOwnerElement)
return;
- document()->clearNodeListCaches();
-
- for (Node* node = this; node; node = node->parentNode()) {
- ASSERT(this == node || !node->isAttributeNode());
- if (!node->hasRareData())
- continue;
- NodeRareData* data = node->rareData();
- if (data->nodeLists())
- data->nodeLists()->invalidateCaches(&attrName);
- if (node->isElementNode())
- static_cast<ElementRareData*>(data)->clearHTMLCollectionCaches();
- }
-}
-
-void Node::invalidateNodeListsCacheAfterChildrenChanged()
-{
- if (hasRareData())
- rareData()->clearChildNodeListCache();
-
if (!document()->shouldInvalidateNodeListCaches())
return;
continue;
NodeRareData* data = node->rareData();
if (data->nodeLists())
- data->nodeLists()->invalidateCaches();
+ data->nodeLists()->invalidateCaches(attrName);
if (node->isElementNode())
- static_cast<ElementRareData*>(data)->clearHTMLCollectionCaches();
+ static_cast<ElementRareData*>(data)->clearHTMLCollectionCaches(attrName);
}
}
{
NodeListAtomicNameCacheMap::const_iterator atomicNameCacheEnd = m_atomicNameCaches.end();
for (NodeListAtomicNameCacheMap::const_iterator it = m_atomicNameCaches.begin(); it != atomicNameCacheEnd; ++it) {
- if (!attrName || it->second->shouldInvalidateOnAttributeChange())
- it->second->invalidateCache();
+ DynamicNodeList* list = it->second;
+ if (!attrName || DynamicNodeListCacheBase::shouldInvalidateTypeOnAttributeChange(list->invalidationType(), *attrName))
+ list->invalidateCache();
}
NodeListNameCacheMap::const_iterator nameCacheEnd = m_nameCaches.end();
for (NodeListNameCacheMap::const_iterator it = m_nameCaches.begin(); it != nameCacheEnd; ++it) {
- if (!attrName || it->second->shouldInvalidateOnAttributeChange())
- it->second->invalidateCache();
+ DynamicNodeList* list = it->second;
+ if (!attrName || DynamicNodeListCacheBase::shouldInvalidateTypeOnAttributeChange(list->invalidationType(), *attrName))
+ list->invalidateCache();
}
if (!attrName)
#endif
-void NodeRareData::createNodeLists()
-{
- setNodeLists(NodeListsNodeData::create());
-}
-
-void NodeRareData::clearChildNodeListCache()
-{
- if (m_childNodeList)
- m_childNodeList->invalidateCache();
-}
-
// It's important not to inline removedLastRef, because we don't want to inline the code to
// delete a Node at each deref call site.
void Node::removedLastRef()
void showTreeForThisAcrossFrame() const;
#endif
- void invalidateNodeListsCacheAfterAttributeChanged(const QualifiedName&, Element* attributeOwnerElement);
- void invalidateNodeListsCacheAfterChildrenChanged();
+ void invalidateNodeListCachesInAncestors(const QualifiedName* attrName = 0, Element* attributeOwnerElement = 0);
NodeListsNodeData* nodeLists();
void removeCachedChildNodeList();
NodeListsNodeData* ensureNodeLists()
{
if (!m_nodeLists)
- createNodeLists();
+ setNodeLists(NodeListsNodeData::create());
return m_nodeLists.get();
}
- void clearChildNodeListCache();
+ void clearChildNodeListCache()
+ {
+ if (m_childNodeList)
+ m_childNodeList->invalidateCache();
+ }
ChildNodeList* childNodeList() const { return m_childNodeList; }
void setChildNodeList(ChildNodeList* list) { m_childNodeList = list; }
void setNeedsFocusAppearanceUpdateSoonAfterAttach(bool needs) { m_needsFocusAppearanceUpdateSoonAfterAttach = needs; }
private:
- void createNodeLists();
TreeScope* m_treeScope;
OwnPtr<NodeListsNodeData> m_nodeLists;
private:
using DynamicNodeListCacheBase::isRootedAtDocument;
- using DynamicNodeListCacheBase::shouldInvalidateOnAttributeChange;
using DynamicNodeListCacheBase::setItemCache;
mutable NodeCacheMap m_idCache;