* dom/Attr.cpp:
(WebCore::Attr::setValue):
(WebCore::Attr::childrenChanged):
* dom/DynamicNodeList.cpp:
(WebCore::DynamicSubtreeNodeList::DynamicSubtreeNodeList):
(WebCore::DynamicSubtreeNodeList::length):
(WebCore::DynamicSubtreeNodeList::itemForwardsFromCurrent):
(WebCore::DynamicSubtreeNodeList::itemBackwardsFromCurrent):
(WebCore::DynamicSubtreeNodeList::item):
(WebCore::DynamicSubtreeNodeList::invalidateCache):
(WebCore::DynamicSubtreeNodeList::Caches::create):
(WebCore::DynamicSubtreeNodeList::Caches::reset):
* dom/DynamicNodeList.h:
* dom/Element.cpp:
(WebCore::Element::updateAfterAttributeChanged):
* dom/Node.cpp:
(WebCore::Node::invalidateNodeListsCacheAfterAttributeChanged):
(WebCore::Node::invalidateNodeListsCacheAfterChildrenChanged):
(WebCore::Node::notifyLocalNodeListsLabelChanged):
(WebCore::Node::itemTypeAttributeChanged):
(WebCore::NodeListsNodeData::invalidateCaches):
(WebCore::NodeListsNodeData::invalidateCachesThatDependOnAttributes):
* dom/NodeRareData.h:
* html/HTMLElement.cpp:
(WebCore::HTMLElement::parseMappedAttribute):
* html/HTMLLabelElement.cpp:
(WebCore::HTMLLabelElement::parseMappedAttribute):
* html/HTMLLabelElement.h:
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@104674
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2012-01-10 Ryosuke Niwa <rniwa@webkit.org>
+
+ Revert r104210. It turned out that this patch makes improving the node list caches harder.
+
+ * dom/Attr.cpp:
+ (WebCore::Attr::setValue):
+ (WebCore::Attr::childrenChanged):
+ * dom/DynamicNodeList.cpp:
+ (WebCore::DynamicSubtreeNodeList::DynamicSubtreeNodeList):
+ (WebCore::DynamicSubtreeNodeList::length):
+ (WebCore::DynamicSubtreeNodeList::itemForwardsFromCurrent):
+ (WebCore::DynamicSubtreeNodeList::itemBackwardsFromCurrent):
+ (WebCore::DynamicSubtreeNodeList::item):
+ (WebCore::DynamicSubtreeNodeList::invalidateCache):
+ (WebCore::DynamicSubtreeNodeList::Caches::create):
+ (WebCore::DynamicSubtreeNodeList::Caches::reset):
+ * dom/DynamicNodeList.h:
+ * dom/Element.cpp:
+ (WebCore::Element::updateAfterAttributeChanged):
+ * dom/Node.cpp:
+ (WebCore::Node::invalidateNodeListsCacheAfterAttributeChanged):
+ (WebCore::Node::invalidateNodeListsCacheAfterChildrenChanged):
+ (WebCore::Node::notifyLocalNodeListsLabelChanged):
+ (WebCore::Node::itemTypeAttributeChanged):
+ (WebCore::NodeListsNodeData::invalidateCaches):
+ (WebCore::NodeListsNodeData::invalidateCachesThatDependOnAttributes):
+ * dom/NodeRareData.h:
+ * html/HTMLElement.cpp:
+ (WebCore::HTMLElement::parseMappedAttribute):
+ * html/HTMLLabelElement.cpp:
+ (WebCore::HTMLLabelElement::parseMappedAttribute):
+ * html/HTMLLabelElement.h:
+
2012-01-10 Sheriff Bot <webkit.review.bot@gmail.com>
Unreviewed, rolling out r104263 and r104381.
createTextChild();
m_ignoreChildrenChanged--;
- invalidateNodeListsCacheAfterAttributeChanged();
+ invalidateNodeListsCacheAfterAttributeChanged(m_attribute->name());
}
void Attr::setValue(const AtomicString& value, ExceptionCode&)
Node::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
- invalidateNodeListsCacheAfterAttributeChanged();
+ invalidateNodeListsCacheAfterAttributeChanged(m_attribute->name());
// FIXME: We should include entity references in the value
namespace WebCore {
-DynamicSubtreeNodeList::SubtreeCaches::SubtreeCaches()
- : m_cachedItem(0)
- , m_isLengthCacheValid(false)
- , m_isItemCacheValid(false)
- , m_domTreeVersionAtTimeOfCaching(0)
-{
-}
-
-void DynamicSubtreeNodeList::SubtreeCaches::setLengthCache(Node* node, unsigned length)
-{
- if (m_isItemCacheValid && !domVersionIsConsistent()) {
- m_cachedItem = node;
- m_isItemCacheValid = false;
- }
- m_cachedLength = length;
- m_isLengthCacheValid = true;
- m_domTreeVersionAtTimeOfCaching = node->document()->domTreeVersion();
-}
-
-void DynamicSubtreeNodeList::SubtreeCaches::setItemCache(Node* item, unsigned offset)
-{
- if (m_isLengthCacheValid && !domVersionIsConsistent())
- m_isLengthCacheValid = false;
- m_cachedItem = item;
- m_cachedItemOffset = offset;
- m_isItemCacheValid = true;
- m_domTreeVersionAtTimeOfCaching = item->document()->domTreeVersion();
-}
-
-void DynamicSubtreeNodeList::SubtreeCaches::reset()
-{
- m_cachedItem = 0;
- m_isLengthCacheValid = false;
- m_isItemCacheValid = false;
-}
-
DynamicSubtreeNodeList::DynamicSubtreeNodeList(PassRefPtr<Node> node)
: DynamicNodeList(node)
+ , m_caches(Caches::create())
{
rootNode()->registerDynamicSubtreeNodeList(this);
}
unsigned DynamicSubtreeNodeList::length() const
{
- if (m_caches.isLengthCacheValid())
- return m_caches.cachedLength();
+ if (m_caches->isLengthCacheValid)
+ return m_caches->cachedLength;
unsigned length = 0;
for (Node* n = node()->firstChild(); n; n = n->traverseNextNode(rootNode()))
length += n->isElementNode() && nodeMatches(static_cast<Element*>(n));
- m_caches.setLengthCache(node(), length);
+ m_caches->cachedLength = length;
+ m_caches->isLengthCacheValid = true;
return length;
}
for (Node* n = start; n; n = n->traverseNextNode(rootNode())) {
if (n->isElementNode() && nodeMatches(static_cast<Element*>(n))) {
if (!remainingOffset) {
- m_caches.setItemCache(n, offset);
+ m_caches->lastItem = n;
+ m_caches->lastItemOffset = offset;
+ m_caches->isItemCacheValid = true;
return n;
}
--remainingOffset;
for (Node* n = start; n; n = n->traversePreviousNode(rootNode())) {
if (n->isElementNode() && nodeMatches(static_cast<Element*>(n))) {
if (!remainingOffset) {
- m_caches.setItemCache(n, offset);
+ m_caches->lastItem = n;
+ m_caches->lastItemOffset = offset;
+ m_caches->isItemCacheValid = true;
return n;
}
++remainingOffset;
{
int remainingOffset = offset;
Node* start = node()->firstChild();
- if (m_caches.isItemCacheValid()) {
- if (offset == m_caches.cachedItemOffset())
- return m_caches.cachedItem();
- if (offset > m_caches.cachedItemOffset() || m_caches.cachedItemOffset() - offset < offset) {
- start = m_caches.cachedItem();
- remainingOffset -= m_caches.cachedItemOffset();
+ if (m_caches->isItemCacheValid) {
+ if (offset == m_caches->lastItemOffset)
+ return m_caches->lastItem;
+ else if (offset > m_caches->lastItemOffset || m_caches->lastItemOffset - offset < offset) {
+ start = m_caches->lastItem;
+ remainingOffset -= m_caches->lastItemOffset;
}
}
void DynamicSubtreeNodeList::invalidateCache()
{
- m_caches.reset();
+ m_caches->reset();
}
DynamicSubtreeNodeList::Caches::Caches()
{
}
-PassRefPtr<DynamicNodeList::Caches> DynamicNodeList::Caches::create()
+PassRefPtr<DynamicSubtreeNodeList::Caches> DynamicSubtreeNodeList::Caches::create()
{
return adoptRef(new Caches());
}
-void DynamicNodeList::Caches::reset()
+void DynamicSubtreeNodeList::Caches::reset()
{
lastItem = 0;
isLengthCacheValid = false;
#ifndef DynamicNodeList_h
#define DynamicNodeList_h
-#include "Document.h"
#include "NodeList.h"
#include <wtf/RefCounted.h>
#include <wtf/Forward.h>
unsigned lastItemOffset;
bool isLengthCacheValid : 1;
bool isItemCacheValid : 1;
-
protected:
Caches();
};
-
DynamicNodeList(PassRefPtr<Node> node)
: m_node(node)
{ }
protected:
DynamicSubtreeNodeList(PassRefPtr<Node> rootNode);
+ mutable RefPtr<Caches> m_caches;
private:
-
- class SubtreeCaches {
- public:
- SubtreeCaches();
-
- bool isLengthCacheValid() const { return m_isLengthCacheValid && domVersionIsConsistent(); }
- bool isItemCacheValid() const { return m_isItemCacheValid && domVersionIsConsistent(); }
-
- unsigned cachedLength() const { return m_cachedLength; }
- Node* cachedItem() const { return m_cachedItem; }
- unsigned cachedItemOffset() const { return m_cachedItemOffset; }
-
- void setLengthCache(Node* nodeForDocumentVersion, unsigned length);
- void setItemCache(Node*, unsigned offset);
- void reset();
-
- private:
- Node* m_cachedItem;
- unsigned m_cachedItemOffset;
- unsigned m_cachedLength;
- bool m_isLengthCacheValid : 1;
- bool m_isItemCacheValid : 1;
-
- bool domVersionIsConsistent() const
- {
- return m_cachedItem && m_cachedItem->document()->domTreeVersion() == m_domTreeVersionAtTimeOfCaching;
- }
- uint64_t m_domTreeVersionAtTimeOfCaching;
- };
-
- mutable SubtreeCaches m_caches;
-
virtual bool isDynamicNodeList() const;
Node* itemForwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const;
Node* itemBackwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const;
void Element::updateAfterAttributeChanged(Attribute* attr)
{
- invalidateNodeListsCacheAfterAttributeChanged();
+ invalidateNodeListsCacheAfterAttributeChanged(attr->name());
if (!AXObjectCache::accessibilityEnabled())
return;
removeNodeListCacheIfPossible(this, data);
}
-void Node::invalidateNodeListsCacheAfterAttributeChanged()
+void Node::invalidateNodeListsCacheAfterAttributeChanged(const QualifiedName& attrName)
{
if (hasRareData() && isAttributeNode()) {
NodeRareData* data = rareData();
ASSERT(!data->nodeLists());
data->clearChildNodeListCache();
}
+
+ // This list should be sync'ed with NodeListsNodeData.
+ if (attrName != classAttr
+#if ENABLE(MICRODATA)
+ && attrName != itemscopeAttr
+ && attrName != itempropAttr
+#endif
+ && attrName != nameAttr)
+ return;
+
+ if (!treeScope()->hasNodeListCaches())
+ return;
+
+ for (Node* node = this; node; node = node->parentNode()) {
+ ASSERT(this == node || !node->isAttributeNode());
+ if (!node->hasRareData())
+ continue;
+ NodeRareData* data = node->rareData();
+ if (!data->nodeLists())
+ continue;
+
+ data->nodeLists()->invalidateCachesThatDependOnAttributes();
+ removeNodeListCacheIfPossible(node, data);
+ }
}
void Node::invalidateNodeListsCacheAfterChildrenChanged()
{
if (hasRareData())
rareData()->clearChildNodeListCache();
+
+ if (!treeScope()->hasNodeListCaches())
+ return;
+ for (Node* node = this; node; node = node->parentNode()) {
+ if (!node->hasRareData())
+ continue;
+ NodeRareData* data = node->rareData();
+ if (!data->nodeLists())
+ continue;
+
+ data->nodeLists()->invalidateCaches();
+
+ NodeListsNodeData::NodeListSet::iterator end = data->nodeLists()->m_listsWithCaches.end();
+ for (NodeListsNodeData::NodeListSet::iterator it = data->nodeLists()->m_listsWithCaches.begin(); it != end; ++it)
+ (*it)->invalidateCache();
+
+ removeNodeListCacheIfPossible(node, data);
+ }
+}
+
+void Node::notifyLocalNodeListsLabelChanged()
+{
+ if (!hasRareData())
+ return;
+ NodeRareData* data = rareData();
+ if (!data->nodeLists())
+ return;
+
+ if (data->nodeLists()->m_labelsNodeListCache)
+ data->nodeLists()->m_labelsNodeListCache->invalidateCache();
}
void Node::removeCachedClassNodeList(ClassNodeList* list, const String& className)
return p;
}
+#if ENABLE(MICRODATA)
+void Node::itemTypeAttributeChanged()
+{
+ Node * rootNode = document();
+
+ if (!rootNode->hasRareData())
+ return;
+
+ NodeRareData* data = rootNode->rareData();
+
+ if (!data->nodeLists())
+ return;
+
+ data->nodeLists()->invalidateMicrodataItemListCaches();
+}
+#endif
+
#ifndef NDEBUG
static void appendAttributeDesc(const Node* node, String& string, const QualifiedName& name, const char* attrDesc)
TagNodeListCacheNS::const_iterator tagCacheNSEnd = m_tagNodeListCacheNS.end();
for (TagNodeListCacheNS::const_iterator it = m_tagNodeListCacheNS.begin(); it != tagCacheNSEnd; ++it)
it->second->invalidateCache();
+ invalidateCachesThatDependOnAttributes();
+}
+void NodeListsNodeData::invalidateCachesThatDependOnAttributes()
+{
ClassNodeListCache::iterator classCacheEnd = m_classNodeListCache.end();
for (ClassNodeListCache::iterator it = m_classNodeListCache.begin(); it != classCacheEnd; ++it)
it->second->invalidateCache();
#if ENABLE(MICRODATA)
invalidateMicrodataItemListCaches();
#endif
-
}
#if ENABLE(MICRODATA)
}
void invalidateCaches();
+ void invalidateCachesThatDependOnAttributes();
#if ENABLE(MICRODATA)
void invalidateMicrodataItemListCaches();
setItemRef(attr->value());
} else if (attr->name() == itemtypeAttr) {
setItemType(attr->value());
+ itemTypeAttributeChanged();
#endif
}
// standard events
HTMLElement::accessKeyAction(sendMouseEvents);
}
+void HTMLLabelElement::parseMappedAttribute(Attribute* attribute)
+{
+ if (attribute->name() == forAttr) {
+ // htmlFor attribute change affects other nodes than this.
+ // Clear the caches to ensure that the labels caches are cleared.
+ if (document())
+ document()->notifyLocalNodeListsLabelChanged();
+ } else
+ HTMLElement::parseMappedAttribute(attribute);
+}
+
} // namespace
virtual void defaultEventHandler(Event*);
void focus(bool restorePreviousSelection = true);
+
+ virtual void parseMappedAttribute(Attribute*);
};
} //namespace