1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2001 Dirk Mueller (mueller (at) kde.org) 5 * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved. 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Library General Public 9 * License as published by the Free Software Foundation; either 10 * version 2 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Library General Public License for more details. 16 * 17 * You should have received a copy of the GNU Library General Public License 18 * along with this library; see the file COPYING.LIB. If not, write to 19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 * Boston, MA 02110-1301, USA. 21 * 22 */ 23 24 #ifndef LiveNodeList_h 25 #define LiveNodeList_h 26 27 #include "HTMLNames.h" 28 #include "core/dom/Document.h" 29 #include "core/dom/NodeList.h" 30 #include "core/html/CollectionType.h" 31 #include "wtf/Forward.h" 32 #include "wtf/RefPtr.h" 33 34 namespace WebCore { 35 36 class Element; 37 38 enum NodeListRootType { 39 NodeListIsRootedAtNode, 40 NodeListIsRootedAtDocument, 41 NodeListIsRootedAtDocumentIfOwnerHasItemrefAttr, 42 }; 43 44 class LiveNodeListBase : public NodeList { 45 public: 46 enum ItemAfterOverrideType { 47 OverridesItemAfter, 48 DoesNotOverrideItemAfter, 49 }; 50 51 LiveNodeListBase(Node* ownerNode, NodeListRootType rootType, NodeListInvalidationType invalidationType, 52 bool shouldOnlyIncludeDirectChildren, CollectionType collectionType, ItemAfterOverrideType itemAfterOverrideType) 53 : m_ownerNode(ownerNode) 54 , m_cachedItem(0) 55 , m_isLengthCacheValid(false) 56 , m_isItemCacheValid(false) 57 , m_rootType(rootType) 58 , m_invalidationType(invalidationType) 59 , m_shouldOnlyIncludeDirectChildren(shouldOnlyIncludeDirectChildren) 60 , m_isNameCacheValid(false) 61 , m_collectionType(collectionType) 62 , m_overridesItemAfter(itemAfterOverrideType == OverridesItemAfter) 63 , m_isItemRefElementsCacheValid(false) 64 { 65 ASSERT(m_rootType == static_cast<unsigned>(rootType)); 66 ASSERT(m_invalidationType == static_cast<unsigned>(invalidationType)); 67 ASSERT(m_collectionType == static_cast<unsigned>(collectionType)); 68 ASSERT(!m_overridesItemAfter || !isNodeList(collectionType)); 69 70 if (collectionType != ChildNodeListType) 71 document()->registerNodeList(this); 72 } 73 74 virtual ~LiveNodeListBase() 75 { 76 if (type() != ChildNodeListType) 77 document()->unregisterNodeList(this); 78 } 79 80 // DOM API 81 virtual unsigned length() const OVERRIDE; 82 virtual Node* item(unsigned offset) const OVERRIDE; 83 84 ALWAYS_INLINE bool hasIdNameCache() const { return !isNodeList(type()); } 85 ALWAYS_INLINE bool isRootedAtDocument() const { return m_rootType == NodeListIsRootedAtDocument || m_rootType == NodeListIsRootedAtDocumentIfOwnerHasItemrefAttr; } 86 ALWAYS_INLINE NodeListInvalidationType invalidationType() const { return static_cast<NodeListInvalidationType>(m_invalidationType); } 87 ALWAYS_INLINE CollectionType type() const { return static_cast<CollectionType>(m_collectionType); } 88 Node* ownerNode() const { return m_ownerNode.get(); } 89 ALWAYS_INLINE void invalidateCache(const QualifiedName* attrName) const 90 { 91 if (!attrName || shouldInvalidateTypeOnAttributeChange(invalidationType(), *attrName)) 92 invalidateCache(); 93 else if (hasIdNameCache() && (*attrName == HTMLNames::idAttr || *attrName == HTMLNames::nameAttr)) 94 invalidateIdNameCacheMaps(); 95 } 96 void invalidateCache() const; 97 void invalidateIdNameCacheMaps() const; 98 99 static bool shouldInvalidateTypeOnAttributeChange(NodeListInvalidationType, const QualifiedName&); 100 101 protected: 102 Document* document() const { return m_ownerNode->document(); } 103 Node* rootNode() const; 104 ContainerNode* rootContainerNode() const; 105 bool overridesItemAfter() const { return m_overridesItemAfter; } 106 107 ALWAYS_INLINE bool isItemCacheValid() const { return m_isItemCacheValid; } 108 ALWAYS_INLINE Node* cachedItem() const { return m_cachedItem; } 109 ALWAYS_INLINE unsigned cachedItemOffset() const { return m_cachedItemOffset; } 110 111 ALWAYS_INLINE bool isLengthCacheValid() const { return m_isLengthCacheValid; } 112 ALWAYS_INLINE unsigned cachedLength() const { return m_cachedLength; } 113 ALWAYS_INLINE void setLengthCache(unsigned length) const 114 { 115 m_cachedLength = length; 116 m_isLengthCacheValid = true; 117 } 118 ALWAYS_INLINE void setItemCache(Node* item, unsigned offset) const 119 { 120 ASSERT(item); 121 m_cachedItem = item; 122 m_cachedItemOffset = offset; 123 m_isItemCacheValid = true; 124 } 125 void setItemCache(Node* item, unsigned offset, unsigned elementsArrayOffset) const; 126 127 ALWAYS_INLINE bool isItemRefElementsCacheValid() const { return m_isItemRefElementsCacheValid; } 128 ALWAYS_INLINE void setItemRefElementsCacheValid() const { m_isItemRefElementsCacheValid = true; } 129 130 ALWAYS_INLINE NodeListRootType rootType() const { return static_cast<NodeListRootType>(m_rootType); } 131 132 bool hasNameCache() const { return m_isNameCacheValid; } 133 void setHasNameCache() const { m_isNameCacheValid = true; } 134 135 bool shouldOnlyIncludeDirectChildren() const { return m_shouldOnlyIncludeDirectChildren; } 136 137 private: 138 Node* itemBeforeOrAfterCachedItem(unsigned offset, ContainerNode* root) const; 139 Node* traverseChildNodeListForwardToOffset(unsigned offset, Node* currentNode, unsigned& currentOffset) const; 140 Element* traverseLiveNodeListFirstElement(ContainerNode* root) const; 141 Element* traverseLiveNodeListForwardToOffset(unsigned offset, Element* currentElement, unsigned& currentOffset, ContainerNode* root) const; 142 bool isLastItemCloserThanLastOrCachedItem(unsigned offset) const; 143 bool isFirstItemCloserThanCachedItem(unsigned offset) const; 144 Node* iterateForPreviousNode(Node* current) const; 145 Node* itemBefore(Node* previousItem) const; 146 147 RefPtr<Node> m_ownerNode; 148 mutable Node* m_cachedItem; 149 mutable unsigned m_cachedLength; 150 mutable unsigned m_cachedItemOffset; 151 mutable unsigned m_isLengthCacheValid : 1; 152 mutable unsigned m_isItemCacheValid : 1; 153 const unsigned m_rootType : 2; 154 const unsigned m_invalidationType : 4; 155 const unsigned m_shouldOnlyIncludeDirectChildren : 1; 156 157 // From HTMLCollection 158 mutable unsigned m_isNameCacheValid : 1; 159 const unsigned m_collectionType : 5; 160 const unsigned m_overridesItemAfter : 1; 161 mutable unsigned m_isItemRefElementsCacheValid : 1; 162 }; 163 164 ALWAYS_INLINE bool LiveNodeListBase::shouldInvalidateTypeOnAttributeChange(NodeListInvalidationType type, const QualifiedName& attrName) 165 { 166 switch (type) { 167 case InvalidateOnClassAttrChange: 168 return attrName == HTMLNames::classAttr; 169 case InvalidateOnNameAttrChange: 170 return attrName == HTMLNames::nameAttr; 171 case InvalidateOnIdNameAttrChange: 172 return attrName == HTMLNames::idAttr || attrName == HTMLNames::nameAttr; 173 case InvalidateOnForAttrChange: 174 return attrName == HTMLNames::forAttr; 175 case InvalidateForFormControls: 176 return attrName == HTMLNames::nameAttr || attrName == HTMLNames::idAttr || attrName == HTMLNames::forAttr 177 || attrName == HTMLNames::formAttr || attrName == HTMLNames::typeAttr; 178 case InvalidateOnHRefAttrChange: 179 return attrName == HTMLNames::hrefAttr; 180 case InvalidateOnItemAttrChange: 181 case DoNotInvalidateOnAttributeChanges: 182 return false; 183 case InvalidateOnAnyAttrChange: 184 return true; 185 } 186 return false; 187 } 188 189 class LiveNodeList : public LiveNodeListBase { 190 public: 191 LiveNodeList(PassRefPtr<Node> ownerNode, CollectionType collectionType, NodeListInvalidationType invalidationType, NodeListRootType rootType = NodeListIsRootedAtNode) 192 : LiveNodeListBase(ownerNode.get(), rootType, invalidationType, collectionType == ChildNodeListType, 193 collectionType, DoesNotOverrideItemAfter) 194 { } 195 196 virtual Node* namedItem(const AtomicString&) const OVERRIDE; 197 virtual bool nodeMatches(Element*) const = 0; 198 199 private: 200 virtual bool isLiveNodeList() const OVERRIDE { return true; } 201 }; 202 203 } // namespace WebCore 204 205 #endif // LiveNodeList_h 206