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 * Copyright (C) 2014 Samsung Electronics. All rights reserved. 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Library General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Library General Public License for more details. 17 * 18 * You should have received a copy of the GNU Library General Public License 19 * along with this library; see the file COPYING.LIB. If not, write to 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 * Boston, MA 02110-1301, USA. 22 * 23 */ 24 25 #ifndef LiveNodeListBase_h 26 #define LiveNodeListBase_h 27 28 #include "core/HTMLNames.h" 29 #include "core/dom/Document.h" 30 #include "core/dom/Element.h" 31 #include "core/dom/ElementTraversal.h" 32 #include "core/dom/NodeTraversal.h" 33 #include "core/html/CollectionType.h" 34 #include "platform/heap/Handle.h" 35 36 namespace WebCore { 37 38 enum NodeListRootType { 39 NodeListIsRootedAtNode, 40 NodeListIsRootedAtDocument 41 }; 42 43 class LiveNodeListBase : public WillBeGarbageCollectedMixin { 44 public: 45 LiveNodeListBase(ContainerNode& ownerNode, NodeListRootType rootType, NodeListInvalidationType invalidationType, 46 CollectionType collectionType) 47 : m_ownerNode(ownerNode) 48 , m_rootType(rootType) 49 , m_invalidationType(invalidationType) 50 , m_collectionType(collectionType) 51 { 52 ASSERT(m_rootType == static_cast<unsigned>(rootType)); 53 ASSERT(m_invalidationType == static_cast<unsigned>(invalidationType)); 54 ASSERT(m_collectionType == static_cast<unsigned>(collectionType)); 55 56 document().registerNodeList(this); 57 } 58 59 virtual ~LiveNodeListBase() 60 { 61 #if !ENABLE(OILPAN) 62 document().unregisterNodeList(this); 63 #endif 64 } 65 66 ContainerNode& rootNode() const; 67 68 void didMoveToDocument(Document& oldDocument, Document& newDocument); 69 ALWAYS_INLINE bool isRootedAtDocument() const { return m_rootType == NodeListIsRootedAtDocument; } 70 ALWAYS_INLINE NodeListInvalidationType invalidationType() const { return static_cast<NodeListInvalidationType>(m_invalidationType); } 71 ALWAYS_INLINE CollectionType type() const { return static_cast<CollectionType>(m_collectionType); } 72 ContainerNode& ownerNode() const { return *m_ownerNode; } 73 74 virtual void invalidateCache(Document* oldDocument = 0) const = 0; 75 void invalidateCacheForAttribute(const QualifiedName*) const; 76 77 static bool shouldInvalidateTypeOnAttributeChange(NodeListInvalidationType, const QualifiedName&); 78 79 protected: 80 Document& document() const { return m_ownerNode->document(); } 81 82 ALWAYS_INLINE NodeListRootType rootType() const { return static_cast<NodeListRootType>(m_rootType); } 83 84 template <class NodeListType> 85 static Element* firstMatchingElement(const NodeListType&); 86 template <class NodeListType> 87 static Element* lastMatchingElement(const NodeListType&); 88 template <class NodeListType> 89 static Element* nextMatchingElement(const NodeListType&, Element& current); 90 template <class NodeListType> 91 static Element* previousMatchingElement(const NodeListType&, Element& current); 92 template <class NodeListType> 93 static Element* traverseMatchingElementsForwardToOffset(const NodeListType&, unsigned offset, Element& currentElement, unsigned& currentOffset); 94 template <class NodeListType> 95 static Element* traverseMatchingElementsBackwardToOffset(const NodeListType&, unsigned offset, Element& currentElement, unsigned& currentOffset); 96 97 void trace(Visitor* visitor) { visitor->trace(m_ownerNode); } 98 99 private: 100 RefPtrWillBeMember<ContainerNode> m_ownerNode; // Cannot be null. 101 const unsigned m_rootType : 1; 102 const unsigned m_invalidationType : 4; 103 const unsigned m_collectionType : 5; 104 }; 105 106 ALWAYS_INLINE bool LiveNodeListBase::shouldInvalidateTypeOnAttributeChange(NodeListInvalidationType type, const QualifiedName& attrName) 107 { 108 switch (type) { 109 case InvalidateOnClassAttrChange: 110 return attrName == HTMLNames::classAttr; 111 case InvalidateOnNameAttrChange: 112 return attrName == HTMLNames::nameAttr; 113 case InvalidateOnIdNameAttrChange: 114 return attrName == HTMLNames::idAttr || attrName == HTMLNames::nameAttr; 115 case InvalidateOnForAttrChange: 116 return attrName == HTMLNames::forAttr; 117 case InvalidateForFormControls: 118 return attrName == HTMLNames::nameAttr || attrName == HTMLNames::idAttr || attrName == HTMLNames::forAttr 119 || attrName == HTMLNames::formAttr || attrName == HTMLNames::typeAttr; 120 case InvalidateOnHRefAttrChange: 121 return attrName == HTMLNames::hrefAttr; 122 case DoNotInvalidateOnAttributeChanges: 123 return false; 124 case InvalidateOnAnyAttrChange: 125 return true; 126 } 127 return false; 128 } 129 130 template <typename NodeListType> 131 Element* LiveNodeListBase::lastMatchingElement(const NodeListType& nodeList) 132 { 133 ContainerNode& root = nodeList.rootNode(); 134 Element* element = ElementTraversal::lastWithin(root); 135 while (element && !isMatchingElement(nodeList, *element)) 136 element = ElementTraversal::previous(*element, &root); 137 return element; 138 } 139 140 template <class NodeListType> 141 Element* LiveNodeListBase::firstMatchingElement(const NodeListType& nodeList) 142 { 143 ContainerNode& root = nodeList.rootNode(); 144 Element* element = ElementTraversal::firstWithin(root); 145 while (element && !isMatchingElement(nodeList, *element)) 146 element = ElementTraversal::next(*element, &root); 147 return element; 148 } 149 150 template <class NodeListType> 151 Element* LiveNodeListBase::nextMatchingElement(const NodeListType& nodeList, Element& current) 152 { 153 ContainerNode& root = nodeList.rootNode(); 154 Element* next = ¤t; 155 do { 156 next = ElementTraversal::next(*next, &root); 157 } while (next && !isMatchingElement(nodeList, *next)); 158 return next; 159 } 160 161 template <class NodeListType> 162 Element* LiveNodeListBase::previousMatchingElement(const NodeListType& nodeList, Element& current) 163 { 164 ContainerNode& root = nodeList.rootNode(); 165 Element* previous = ¤t; 166 do { 167 previous = ElementTraversal::previous(*previous, &root); 168 } while (previous && !isMatchingElement(nodeList, *previous)); 169 return previous; 170 } 171 172 template <class NodeListType> 173 Element* LiveNodeListBase::traverseMatchingElementsForwardToOffset(const NodeListType& nodeList, unsigned offset, Element& currentElement, unsigned& currentOffset) 174 { 175 ASSERT(currentOffset < offset); 176 Element* next = ¤tElement; 177 while ((next = nextMatchingElement(nodeList, *next))) { 178 if (++currentOffset == offset) 179 return next; 180 } 181 return 0; 182 } 183 184 template <class NodeListType> 185 Element* LiveNodeListBase::traverseMatchingElementsBackwardToOffset(const NodeListType& nodeList, unsigned offset, Element& currentElement, unsigned& currentOffset) 186 { 187 ASSERT(currentOffset > offset); 188 Element* previous = ¤tElement; 189 while ((previous = previousMatchingElement(nodeList, *previous))) { 190 if (--currentOffset == offset) 191 return previous; 192 } 193 return 0; 194 } 195 196 } // namespace WebCore 197 198 #endif // LiveNodeListBase_h 199