#include "HTMLNames.h"
#include "core/dom/Document.h"
#include "core/dom/NodeList.h"
+#include "core/html/CollectionIndexCache.h"
#include "core/html/CollectionType.h"
#include "wtf/Forward.h"
#include "wtf/RefPtr.h"
class LiveNodeListBase {
public:
- enum ItemAfterOverrideType {
- OverridesItemAfter,
- DoesNotOverrideItemAfter,
- };
-
LiveNodeListBase(ContainerNode* ownerNode, NodeListRootType rootType, NodeListInvalidationType invalidationType,
- bool shouldOnlyIncludeDirectChildren, CollectionType collectionType, ItemAfterOverrideType itemAfterOverrideType)
+ CollectionType collectionType)
: m_ownerNode(ownerNode)
- , m_cachedItem(0)
- , m_isLengthCacheValid(false)
, m_rootType(rootType)
, m_invalidationType(invalidationType)
- , m_shouldOnlyIncludeDirectChildren(shouldOnlyIncludeDirectChildren)
, m_collectionType(collectionType)
- , m_overridesItemAfter(itemAfterOverrideType == OverridesItemAfter)
{
ASSERT(m_ownerNode);
ASSERT(m_rootType == static_cast<unsigned>(rootType));
ASSERT(m_invalidationType == static_cast<unsigned>(invalidationType));
ASSERT(m_collectionType == static_cast<unsigned>(collectionType));
- ASSERT(!m_overridesItemAfter || !isLiveNodeListType(collectionType));
- if (collectionType != ChildNodeListType)
- document().registerNodeList(this);
+ document().registerNodeList(this);
}
virtual ~LiveNodeListBase()
{
- if (type() != ChildNodeListType)
- document().unregisterNodeList(this);
+ document().unregisterNodeList(this);
}
- unsigned length() const;
- Node* item(unsigned offset) const;
+ ContainerNode& rootNode() const;
+ void didMoveToDocument(Document& oldDocument, Document& newDocument);
ALWAYS_INLINE bool hasIdNameCache() const { return !isLiveNodeListType(type()); }
ALWAYS_INLINE bool isRootedAtDocument() const { return m_rootType == NodeListIsRootedAtDocument || m_rootType == NodeListIsRootedAtDocumentIfOwnerHasItemrefAttr; }
ALWAYS_INLINE NodeListInvalidationType invalidationType() const { return static_cast<NodeListInvalidationType>(m_invalidationType); }
else if (hasIdNameCache() && (*attrName == HTMLNames::idAttr || *attrName == HTMLNames::nameAttr))
invalidateIdNameCacheMaps();
}
- virtual void invalidateCache() const;
+ virtual void invalidateCache(Document* oldDocument = 0) const = 0;
static bool shouldInvalidateTypeOnAttributeChange(NodeListInvalidationType, const QualifiedName&);
protected:
Document& document() const { return m_ownerNode->document(); }
- ContainerNode& rootNode() const;
- bool overridesItemAfter() const { return m_overridesItemAfter; }
-
- ALWAYS_INLINE Node* cachedItem() const { return m_cachedItem; }
- ALWAYS_INLINE unsigned cachedItemOffset() const { ASSERT(cachedItem()); return m_cachedItemOffset; }
-
- ALWAYS_INLINE bool isLengthCacheValid() const { return m_isLengthCacheValid; }
- ALWAYS_INLINE unsigned cachedLength() const { return m_cachedLength; }
- ALWAYS_INLINE void setLengthCache(unsigned length) const
- {
- m_cachedLength = length;
- m_isLengthCacheValid = true;
- }
- ALWAYS_INLINE void setItemCache(Node* item, unsigned offset) const
- {
- ASSERT(item);
- m_cachedItem = item;
- m_cachedItemOffset = offset;
- }
ALWAYS_INLINE NodeListRootType rootType() const { return static_cast<NodeListRootType>(m_rootType); }
- bool shouldOnlyIncludeDirectChildren() const { return m_shouldOnlyIncludeDirectChildren; }
+
+ template <typename Collection>
+ static Element* iterateForPreviousNode(const Collection&, Node* current);
+ template <typename Collection>
+ static Element* itemBefore(const Collection&, const Element* previousItem);
private:
- Node* itemBeforeOrAfterCachedItem(unsigned offset, const ContainerNode& root) const;
- bool isLastItemCloserThanLastOrCachedItem(unsigned offset) const;
- bool isFirstItemCloserThanCachedItem(unsigned offset) const;
- Node* iterateForPreviousNode(Node* current) const;
- Node* itemBefore(const Node* previousItem) const;
void invalidateIdNameCacheMaps() const;
RefPtr<ContainerNode> m_ownerNode; // Cannot be null.
- mutable Node* m_cachedItem;
- mutable unsigned m_cachedLength;
- mutable unsigned m_cachedItemOffset;
- mutable unsigned m_isLengthCacheValid : 1;
const unsigned m_rootType : 2;
const unsigned m_invalidationType : 4;
- const unsigned m_shouldOnlyIncludeDirectChildren : 1;
const unsigned m_collectionType : 5;
-
- // From HTMLCollection
- const unsigned m_overridesItemAfter : 1;
};
ALWAYS_INLINE bool LiveNodeListBase::shouldInvalidateTypeOnAttributeChange(NodeListInvalidationType type, const QualifiedName& attrName)
|| attrName == HTMLNames::formAttr || attrName == HTMLNames::typeAttr;
case InvalidateOnHRefAttrChange:
return attrName == HTMLNames::hrefAttr;
- case InvalidateOnItemAttrChange:
case DoNotInvalidateOnAttributeChanges:
return false;
case InvalidateOnAnyAttrChange:
class LiveNodeList : public NodeList, public LiveNodeListBase {
public:
LiveNodeList(PassRefPtr<ContainerNode> ownerNode, CollectionType collectionType, NodeListInvalidationType invalidationType, NodeListRootType rootType = NodeListIsRootedAtNode)
- : LiveNodeListBase(ownerNode.get(), rootType, invalidationType, collectionType == ChildNodeListType,
- collectionType, DoesNotOverrideItemAfter)
+ : LiveNodeListBase(ownerNode.get(), rootType, invalidationType,
+ collectionType)
{ }
- virtual unsigned length() const OVERRIDE FINAL { return LiveNodeListBase::length(); }
- virtual Node* item(unsigned offset) const OVERRIDE FINAL { return LiveNodeListBase::item(offset); }
- virtual Node* namedItem(const AtomicString&) const OVERRIDE FINAL;
+ virtual unsigned length() const OVERRIDE FINAL { return m_collectionIndexCache.nodeCount(*this); }
+ virtual Node* item(unsigned offset) const OVERRIDE FINAL { return m_collectionIndexCache.nodeAt(*this, offset); }
virtual bool nodeMatches(const Element&) const = 0;
- // Avoid ambiguity since both NodeList and LiveNodeListBase have an ownerNode() method.
- using LiveNodeListBase::ownerNode;
- Node* traverseToFirstElement(const ContainerNode& root) const;
- Node* traverseForwardToOffset(unsigned offset, Node& currentNode, unsigned& currentOffset, const ContainerNode& root) const;
+ virtual void invalidateCache(Document* oldDocument) const OVERRIDE FINAL;
+ bool shouldOnlyIncludeDirectChildren() const { return false; }
+
+ // Collection IndexCache API.
+ bool canTraverseBackward() const { return true; }
+ Element* itemBefore(const Element* previousItem) const;
+ Element* traverseToFirstElement(const ContainerNode& root) const;
+ Element* traverseForwardToOffset(unsigned offset, Element& currentNode, unsigned& currentOffset, const ContainerNode& root) const;
private:
- virtual bool isLiveNodeList() const OVERRIDE FINAL { return true; }
+ virtual Node* virtualOwnerNode() const OVERRIDE FINAL;
+
+ mutable CollectionIndexCache<LiveNodeList, Element> m_collectionIndexCache;
};
} // namespace WebCore