Changeset 123281 in webkit
- Timestamp:
- Jul 20, 2012 6:03:17 PM (12 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 25 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r123276 r123281 1 2012-07-18 Ryosuke Niwa <rniwa@webkit.org> 2 3 Unify HTMLCollection and DynamicNodeList 4 https://bugs.webkit.org/show_bug.cgi?id=91335 5 6 Reviewed by Anders Carlsson. 7 8 This is the grand unification of HTMLCollection and DynamicNodeList. 9 10 It merges implementations of item() and length() in ChildNodeList, DynamicNodeList, 11 and HTMLCollection. The unified implementation is based on the one used for HTMLCollection, 12 that has been improved over the last few days; see r122660 and r122672 for examples. 13 14 There are five key changes: 15 1. Made itemBeforeOrAfter aware of DynamicNodeList. 16 2. itemBeforeOrAfter and related functions take and return Node* to support ChildNodeList. 17 3. Renamed InvalidCollectionType to NodeListCollectionType since DynamicNodeLists need to be 18 identified itemBeforeOrAfter. 19 4. Renamed itemAfter to virtualItemAfter in subclasses of HTMLCollection, and devirtualized 20 itemAfter used in common cases to avoid performance regressions. To make this intent clear, 21 SupportItemBefore and DoNotSupportItemBefore have been renamed to DoesNotOverrideItemAfter 22 and OverridesItemAfter. This change also help us detect a subclass of HTMLCollection that 23 passes in a wrong value to ItemBeforeSupportType by making forward iterations fail (hit an 24 assertion or doesn't iterate at all) as well as backward iterations. 25 5. Restricted the use of elementsArrayOffset to subclasses that provide virtualItemAfter. 26 27 This patch completes my effort to share code between HTMLCollection and DynamicNodeList. 28 29 * dom/ChildNodeList.cpp: 30 (WebCore::ChildNodeList::ChildNodeList): 31 (WebCore): Removed length() and item(). 32 (WebCore::ChildNodeList::nodeMatches): 33 * dom/ChildNodeList.h: 34 (ChildNodeList): 35 * dom/ClassNodeList.cpp: 36 (WebCore::ClassNodeList::ClassNodeList): 37 * dom/Document.cpp: 38 (WebCore::Document::registerNodeListCache): 39 (WebCore::Document::unregisterNodeListCache): 40 * dom/DynamicNodeList.cpp: 41 (WebCore::DynamicNodeListCacheBase::invalidateCache): 42 (WebCore::DynamicNodeList::length): 43 (WebCore::DynamicNodeList::item): 44 * dom/DynamicNodeList.h: 45 (WebCore::DynamicNodeListCacheBase::DynamicNodeListCacheBase): Takes new boolean argument 46 shouldOnlyIncludeDirectChildren indicating whether the non-child descendents should be 47 included or not. This is necessary to identify ChildNodeList in itemBeforeOrAfter. 48 (WebCore::DynamicNodeListCacheBase::ownerNode): Moved from DynamicNodeListCacheBase and 49 HTMLCollectionCacheBase. 50 (WebCore::DynamicNodeListCacheBase::document): Moved from DynamicNodeListCacheBase. 51 (WebCore::DynamicNodeListCacheBase::rootNode): Ditto. 52 (WebCore::DynamicNodeListCacheBase::overridesItemAfter): Renamed from supportsItemBefore 53 and the return value has been negated. 54 (WebCore::DynamicNodeListCacheBase::shouldOnlyIncludeDirectChildren): Added. 55 (WebCore::DynamicNodeListCacheBase): 56 (WebCore::DynamicNodeList::DynamicNodeList): Takes NodeListType to determine the value of 57 shouldOnlyIncludeDirectChildren. 58 (DynamicNodeList): 59 (WebCore::DynamicSubtreeNodeList::~DynamicSubtreeNodeList): 60 (WebCore::DynamicSubtreeNodeList::DynamicSubtreeNodeList): 61 * dom/MicroDataItemList.cpp: 62 (WebCore::MicroDataItemList::MicroDataItemList): 63 * dom/NameNodeList.cpp: 64 (WebCore::NameNodeList::NameNodeList): 65 * dom/TagNodeList.cpp: 66 (WebCore::TagNodeList::TagNodeList): 67 * html/CollectionType.h: 68 * html/HTMLAllCollection.cpp: 69 (WebCore::HTMLAllCollection::HTMLAllCollection): 70 * html/HTMLCollection.cpp: 71 (WebCore::shouldOnlyIncludeDirectChildren): 72 (WebCore::rootTypeFromCollectionType): 73 (WebCore::invalidationTypeExcludingIdAndNameAttributes): 74 (WebCore::HTMLCollection::HTMLCollection): 75 (WebCore::HTMLCollection::create): 76 (WebCore::HTMLCollection::~HTMLCollection): 77 (WebCore::isAcceptableElement): 78 (WebCore::firstNode): Extracted from itemBeforeOrAfter. 79 (WebCore::DynamicNodeListCacheBase::iterateForNextNode): Ditto. 80 (WebCore::DynamicNodeListCacheBase::itemBeforeOrAfter): Takes and returns Node*. 81 Special case ChildNodeList since there is no need to skip any node. When "this" is a 82 node list, call nodeMatches instead of isAcceptableElement. 83 (WebCore::DynamicNodeListCacheBase::itemBefore): No longer takes offsetInArray since 84 the use of elementsArrayOffset has been restricted to HTMLCollections that provides 85 virtualItemAfter. 86 (WebCore::DynamicNodeListCacheBase::itemAfter): Calls virtualItemAfter if necessary. 87 Otherwise assert offsetInArray is zero since we should never be using this variable 88 when virtualItemAfter is not provided. 89 (WebCore::DynamicNodeListCacheBase::isLastItemCloserThanLastOrCachedItem): 90 (WebCore::DynamicNodeListCacheBase::isFirstItemCloserThanCachedItem): 91 (WebCore::DynamicNodeListCacheBase::setItemCache): Updates m_cachedElementsArrayOffset 92 in HTMLCollection if and only if virtualItemAfter is provided. This is safe because 93 node lists never provide virtualItemAfter. 94 (WebCore::DynamicNodeListCacheBase::cachedElementsArrayOffset): Similarly, returns 95 m_cachedElementsArrayOffset if virtualItemAfter is provided. 96 (WebCore::DynamicNodeListCacheBase::lengthCommon): 97 (WebCore::DynamicNodeListCacheBase::itemCommon): Note that supportsItemBefore() is 98 equivalent to !overridesItemAfter() here. 99 (WebCore::DynamicNodeListCacheBase::itemBeforeOrAfterCachedItem): Uses Node* through 100 out the function. Since itemBefore never uses offsetInArray, always sets 0 for that. 101 Note that we never call itemBefore and virtualItemAfter on the same object. 102 (WebCore::HTMLCollection::virtualItemAfter): Added only to make the class "concrete". 103 (WebCore::HTMLCollection::namedItem): 104 (WebCore::HTMLCollection::updateNameCache): 105 (WebCore::HTMLCollection::tags): 106 * html/HTMLCollection.h: 107 (WebCore::HTMLCollectionCacheBase::HTMLCollectionCacheBase): 108 (HTMLCollectionCacheBase): 109 (WebCore::HTMLCollection::length): 110 (WebCore::HTMLCollection::item): 111 (WebCore::HTMLCollection::base): 112 (HTMLCollection): 113 * html/HTMLFormCollection.cpp: 114 (WebCore::HTMLFormCollection::HTMLFormCollection): 115 (WebCore::HTMLFormCollection::virtualItemAfter): 116 * html/HTMLFormCollection.h: 117 (HTMLFormCollection): 118 * html/HTMLNameCollection.cpp: 119 (WebCore::HTMLNameCollection::HTMLNameCollection): 120 (WebCore::HTMLNameCollection::virtualItemAfter): 121 * html/HTMLNameCollection.h: 122 (HTMLNameCollection): 123 * html/HTMLOptionsCollection.cpp: 124 (WebCore::HTMLOptionsCollection::HTMLOptionsCollection): 125 * html/HTMLPropertiesCollection.cpp: 126 (WebCore::HTMLPropertiesCollection::HTMLPropertiesCollection): 127 (WebCore::HTMLPropertiesCollection::virtualItemAfter): 128 (WebCore::HTMLPropertiesCollection::updateNameCache): 129 * html/HTMLPropertiesCollection.h: 130 (HTMLPropertiesCollection): 131 * html/HTMLTableRowsCollection.cpp: 132 (WebCore::HTMLTableRowsCollection::HTMLTableRowsCollection): 133 (WebCore::HTMLTableRowsCollection::virtualItemAfter): 134 * html/HTMLTableRowsCollection.h: 135 (HTMLTableRowsCollection): 136 * html/LabelsNodeList.cpp: 137 (WebCore::LabelsNodeList::LabelsNodeList): 138 * html/RadioNodeList.cpp: 139 (WebCore::RadioNodeList::RadioNodeList): 140 1 141 2012-07-20 Joshua Bell <jsbell@chromium.org> 2 142 -
trunk/Source/WebCore/dom/ChildNodeList.cpp
r122498 r123281 29 29 30 30 ChildNodeList::ChildNodeList(PassRefPtr<Node> node) 31 : DynamicNodeList(node, NodeListIsRootedAtNode, DoNotInvalidateOnAttributeChanges)31 : DynamicNodeList(node, ChildNodeListType, NodeListIsRootedAtNode, DoNotInvalidateOnAttributeChanges) 32 32 { 33 33 } … … 38 38 } 39 39 40 unsigned ChildNodeList::length() const41 {42 if (isLengthCacheValid())43 return cachedLength();44 45 unsigned len = 0;46 for (Node* n = rootNode()->firstChild(); n; n = n->nextSibling())47 len++;48 49 setLengthCache(len);50 51 return len;52 }53 54 Node* ChildNodeList::item(unsigned index) const55 {56 unsigned int pos = 0;57 Node* n = rootNode()->firstChild();58 59 if (isItemCacheValid()) {60 if (index == cachedItemOffset())61 return cachedItem();62 63 int diff = index - cachedItemOffset();64 unsigned dist = abs(diff);65 if (dist < index) {66 n = cachedItem();67 pos = cachedItemOffset();68 }69 }70 71 if (isLengthCacheValid()) {72 if (index >= cachedLength())73 return 0;74 75 int diff = index - pos;76 unsigned dist = abs(diff);77 if (dist > cachedLength() - 1 - index) {78 n = rootNode()->lastChild();79 pos = cachedLength() - 1;80 }81 }82 83 if (pos <= index) {84 while (n && pos < index) {85 n = n->nextSibling();86 ++pos;87 }88 } else {89 while (n && pos > index) {90 n = n->previousSibling();91 --pos;92 }93 }94 95 if (n) {96 setItemCache(n, pos);97 return n;98 }99 100 return 0;101 }102 103 40 bool ChildNodeList::nodeMatches(Element* testNode) const 104 41 { 105 // Note: Due to the overrides of the length and item functions above, 106 // this function will be called only by DynamicNodeList::itemWithName, 42 // This function will be called only by DynamicNodeList::itemWithName, 107 43 // for an element that was located with getElementById. 108 44 return testNode->parentNode() == rootNode(); -
trunk/Source/WebCore/dom/ChildNodeList.h
r105408 r123281 39 39 virtual ~ChildNodeList(); 40 40 41 virtual unsigned length() const;42 virtual Node* item(unsigned index) const;43 44 41 protected: 45 42 ChildNodeList(PassRefPtr<Node> rootNode); -
trunk/Source/WebCore/dom/ClassNodeList.cpp
r122498 r123281 38 38 39 39 ClassNodeList::ClassNodeList(PassRefPtr<Node> rootNode, const String& classNames) 40 : DynamicSubtreeNodeList(rootNode, InvalidateOnClassAttrChange)40 : DynamicSubtreeNodeList(rootNode, ClassNodeListType, InvalidateOnClassAttrChange) 41 41 , m_classNames(classNames, document()->inQuirksMode()) 42 42 , m_originalClassNames(classNames) -
trunk/Source/WebCore/dom/Document.cpp
r123248 r123281 3883 3883 void Document::registerNodeListCache(DynamicNodeListCacheBase* list) 3884 3884 { 3885 if (list->type() != InvalidCollectionType)3885 if (list->type() != NodeListCollectionType) 3886 3886 m_nodeListCounts[InvalidateOnIdNameAttrChange]++; 3887 3887 m_nodeListCounts[list->invalidationType()]++; … … 3892 3892 void Document::unregisterNodeListCache(DynamicNodeListCacheBase* list) 3893 3893 { 3894 if (list->type() != InvalidCollectionType)3894 if (list->type() != NodeListCollectionType) 3895 3895 m_nodeListCounts[InvalidateOnIdNameAttrChange]--; 3896 3896 m_nodeListCounts[list->invalidationType()]--; -
trunk/Source/WebCore/dom/DynamicNodeList.cpp
r122621 r123281 37 37 m_isItemCacheValid = false; 38 38 m_isNameCacheValid = false; 39 if (type() == InvalidCollectionType)39 if (type() == NodeListCollectionType) 40 40 return; 41 41 … … 52 52 } 53 53 54 unsigned Dynamic SubtreeNodeList::length() const54 unsigned DynamicNodeList::length() const 55 55 { 56 if (isLengthCacheValid()) 57 return cachedLength(); 58 59 unsigned length = 0; 60 Node* rootNode = this->rootNode(); 61 62 for (Node* n = rootNode->firstChild(); n; n = n->traverseNextNode(rootNode)) 63 length += n->isElementNode() && nodeMatches(static_cast<Element*>(n)); 64 65 setLengthCache(length); 66 67 return length; 56 return lengthCommon(); 68 57 } 69 58 70 Node* Dynamic SubtreeNodeList::itemForwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const59 Node* DynamicNodeList::item(unsigned offset) const 71 60 { 72 ASSERT(remainingOffset >= 0); 73 Node* rootNode = this->rootNode(); 74 for (Node* n = start; n; n = n->traverseNextNode(rootNode)) { 75 if (n->isElementNode() && nodeMatches(static_cast<Element*>(n))) { 76 if (!remainingOffset) { 77 setItemCache(n, offset); 78 return n; 79 } 80 --remainingOffset; 81 } 82 } 83 84 return 0; // no matching node in this subtree 85 } 86 87 Node* DynamicSubtreeNodeList::itemBackwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const 88 { 89 ASSERT(remainingOffset < 0); 90 Node* rootNode = this->rootNode(); 91 for (Node* n = start; n; n = n->traversePreviousNode(rootNode)) { 92 if (n->isElementNode() && nodeMatches(static_cast<Element*>(n))) { 93 if (!remainingOffset) { 94 setItemCache(n, offset); 95 return n; 96 } 97 ++remainingOffset; 98 } 99 } 100 101 return 0; // no matching node in this subtree 102 } 103 104 Node* DynamicSubtreeNodeList::item(unsigned offset) const 105 { 106 int remainingOffset = offset; 107 Node* start = rootNode()->firstChild(); 108 if (isItemCacheValid()) { 109 if (offset == cachedItemOffset()) 110 return cachedItem(); 111 if (offset > cachedItemOffset() || cachedItemOffset() - offset < offset) { 112 start = cachedItem(); 113 remainingOffset -= cachedItemOffset(); 114 } 115 } 116 117 if (remainingOffset < 0) 118 return itemBackwardsFromCurrent(start, offset, remainingOffset); 119 return itemForwardsFromCurrent(start, offset, remainingOffset); 61 return itemCommon(offset); 120 62 } 121 63 -
trunk/Source/WebCore/dom/DynamicNodeList.h
r122873 r123281 44 44 class DynamicNodeListCacheBase { 45 45 public: 46 enum Item BeforeSupportType {47 DoNotSupportItemBefore,48 SupportItemBefore,46 enum ItemAfterOverrideType { 47 OverridesItemAfter, 48 DoesNotOverrideItemAfter, 49 49 }; 50 50 51 DynamicNodeListCacheBase(NodeListRootType rootType, NodeListInvalidationType invalidationType, 52 CollectionType collectionType = InvalidCollectionType, ItemBeforeSupportType itemBeforeSupportType = DoNotSupportItemBefore) 53 : m_cachedItem(0) 51 DynamicNodeListCacheBase(Node* ownerNode, NodeListRootType rootType, NodeListInvalidationType invalidationType, 52 bool shouldOnlyIncludeDirectChildren, CollectionType collectionType, ItemAfterOverrideType itemAfterOverrideType) 53 : m_ownerNode(ownerNode) 54 , m_cachedItem(0) 54 55 , m_isLengthCacheValid(false) 55 56 , m_isItemCacheValid(false) 56 57 , m_rootedAtDocument(rootType == NodeListIsRootedAtDocument) 57 58 , m_invalidationType(invalidationType) 59 , m_shouldOnlyIncludeDirectChildren(shouldOnlyIncludeDirectChildren) 58 60 , m_isNameCacheValid(false) 59 61 , m_collectionType(collectionType) 60 , m_ supportsItemBefore(itemBeforeSupportType == SupportItemBefore)62 , m_overridesItemAfter(itemAfterOverrideType == OverridesItemAfter) 61 63 { 62 64 ASSERT(m_invalidationType == static_cast<unsigned>(invalidationType)); 63 65 ASSERT(m_collectionType == static_cast<unsigned>(collectionType)); 66 ASSERT(!m_overridesItemAfter || m_collectionType != NodeListCollectionType); 64 67 } 65 68 … … 68 71 ALWAYS_INLINE NodeListInvalidationType invalidationType() const { return static_cast<NodeListInvalidationType>(m_invalidationType); } 69 72 ALWAYS_INLINE CollectionType type() const { return static_cast<CollectionType>(m_collectionType); } 70 73 Node* ownerNode() const { return m_ownerNode.get(); } 71 74 ALWAYS_INLINE void invalidateCache(const QualifiedName* attrName) const 72 75 { … … 79 82 80 83 protected: 81 bool supportsItemBefore() const { return m_supportsItemBefore; } 84 Document* document() const { return m_ownerNode->document(); } 85 Node* rootNode() const 86 { 87 if (isRootedAtDocument() && m_ownerNode->inDocument()) 88 return m_ownerNode->document(); 89 return m_ownerNode.get(); 90 } 91 bool overridesItemAfter() const { return m_overridesItemAfter; } 82 92 83 93 ALWAYS_INLINE bool isItemCacheValid() const { return m_isItemCacheValid; } 84 94 ALWAYS_INLINE Node* cachedItem() const { return m_cachedItem; } 85 95 ALWAYS_INLINE unsigned cachedItemOffset() const { return m_cachedItemOffset; } 96 unsigned cachedElementsArrayOffset() const; 86 97 87 98 ALWAYS_INLINE bool isLengthCacheValid() const { return m_isLengthCacheValid; } … … 99 110 m_isItemCacheValid = true; 100 111 } 112 void setItemCache(Node* item, unsigned offset, unsigned elementsArrayOffset) const; 101 113 102 114 bool hasNameCache() const { return m_isNameCacheValid; } 103 115 void setHasNameCache() const { m_isNameCacheValid = true; } 104 116 117 unsigned lengthCommon() const; 118 Node* itemCommon(unsigned offset) const; 119 Node* itemBeforeOrAfterCachedItem(unsigned offset) const; 120 Node* itemAfter(unsigned&, Node* previousItem) const; 121 105 122 private: 123 bool shouldOnlyIncludeDirectChildren() const { return m_shouldOnlyIncludeDirectChildren; } 124 bool isLastItemCloserThanLastOrCachedItem(unsigned offset) const; 125 bool isFirstItemCloserThanCachedItem(unsigned offset) const; 126 template <bool forward> Node* iterateForNextNode(Node* current) const; 127 template<bool forward> Node* itemBeforeOrAfter(Node* previousItem) const; 128 Node* itemBefore(Node* previousItem) const; 129 130 RefPtr<Node> m_ownerNode; 106 131 mutable Node* m_cachedItem; 107 132 mutable unsigned m_cachedLength; … … 111 136 const unsigned m_rootedAtDocument : 1; 112 137 const unsigned m_invalidationType : 4; 138 const unsigned m_shouldOnlyIncludeDirectChildren : 1; 113 139 114 140 // From HTMLCollection 115 141 mutable unsigned m_isNameCacheValid : 1; 116 142 const unsigned m_collectionType : 5; 117 const unsigned m_ supportsItemBefore: 1;143 const unsigned m_overridesItemAfter : 1; 118 144 }; 119 145 … … 157 183 MicroDataItemListType, 158 184 }; 159 DynamicNodeList(PassRefPtr<Node> ownerNode, NodeListRootType rootType, NodeListInvalidationType invalidationType) 160 : DynamicNodeListCacheBase(rootType, invalidationType) 161 , m_ownerNode(ownerNode) 185 DynamicNodeList(PassRefPtr<Node> ownerNode, NodeListType type, NodeListRootType rootType, NodeListInvalidationType invalidationType) 186 : DynamicNodeListCacheBase(ownerNode.get(), rootType, invalidationType, type == ChildNodeListType, NodeListCollectionType, DoesNotOverrideItemAfter) 162 187 { } 163 188 virtual ~DynamicNodeList() { } 164 189 165 190 // DOM methods & attributes for NodeList 166 virtual unsigned length() const = 0;167 virtual Node* item(unsigned index) const = 0;191 virtual unsigned length() const OVERRIDE; 192 virtual Node* item(unsigned offset) const OVERRIDE; 168 193 virtual Node* itemWithName(const AtomicString&) const; 169 194 170 195 // Other methods (not part of DOM) 171 Node* ownerNode() const { return m_ownerNode.get(); }172 173 protected:174 Node* rootNode() const175 {176 if (isRootedAtDocument() && m_ownerNode->inDocument())177 return m_ownerNode->document();178 return m_ownerNode.get();179 }180 Document* document() const { return m_ownerNode->document(); }181 196 virtual bool nodeMatches(Element*) const = 0; 182 197 183 198 private: 184 199 virtual bool isDynamicNodeList() const OVERRIDE { return true; } 185 RefPtr<Node> m_ownerNode;186 200 }; 187 201 … … 192 206 document()->unregisterNodeListCache(this); 193 207 } 194 virtual unsigned length() const OVERRIDE;195 virtual Node* item(unsigned index) const OVERRIDE;196 208 197 209 protected: 198 DynamicSubtreeNodeList(PassRefPtr<Node> node, NodeList InvalidationType invalidationType, NodeListRootType rootType = NodeListIsRootedAtNode)199 : DynamicNodeList(node, rootType, invalidationType)210 DynamicSubtreeNodeList(PassRefPtr<Node> node, NodeListType type, NodeListInvalidationType invalidationType, NodeListRootType rootType = NodeListIsRootedAtNode) 211 : DynamicNodeList(node, type, rootType, invalidationType) 200 212 { 201 213 document()->registerNodeListCache(this); -
trunk/Source/WebCore/dom/MicroDataItemList.cpp
r122498 r123281 46 46 47 47 MicroDataItemList::MicroDataItemList(PassRefPtr<Node> rootNode, const String& typeNames) 48 : DynamicSubtreeNodeList(rootNode, InvalidateOnItemAttrChange)48 : DynamicSubtreeNodeList(rootNode, MicroDataItemListType, InvalidateOnItemAttrChange) 49 49 , m_typeNames(typeNames, document()->inQuirksMode()) 50 50 , m_originalTypeNames(typeNames) -
trunk/Source/WebCore/dom/NameNodeList.cpp
r122498 r123281 34 34 35 35 NameNodeList::NameNodeList(PassRefPtr<Node> rootNode, const AtomicString& name) 36 : DynamicSubtreeNodeList(rootNode, InvalidateOnNameAttrChange)36 : DynamicSubtreeNodeList(rootNode, NameNodeListType, InvalidateOnNameAttrChange) 37 37 , m_name(name) 38 38 { -
trunk/Source/WebCore/dom/TagNodeList.cpp
r122498 r123281 32 32 33 33 TagNodeList::TagNodeList(PassRefPtr<Node> rootNode, const AtomicString& namespaceURI, const AtomicString& localName) 34 : DynamicSubtreeNodeList(rootNode, DoNotInvalidateOnAttributeChanges)34 : DynamicSubtreeNodeList(rootNode, TagNodeListType, DoNotInvalidateOnAttributeChanges) 35 35 , m_namespaceURI(namespaceURI) 36 36 , m_localName(localName) -
trunk/Source/WebCore/html/CollectionType.h
r122531 r123281 62 62 63 63 FormControls, 64 InvalidCollectionType64 NodeListCollectionType 65 65 }; 66 66 -
trunk/Source/WebCore/html/HTMLAllCollection.cpp
r122660 r123281 37 37 38 38 HTMLAllCollection::HTMLAllCollection(Document* document) 39 : HTMLCollection(document, DocAll, SupportItemBefore)39 : HTMLCollection(document, DocAll, DoesNotOverrideItemAfter) 40 40 { 41 41 } -
trunk/Source/WebCore/html/HTMLCollection.cpp
r122930 r123281 70 70 case TableTBodies: 71 71 return true; 72 case InvalidCollectionType:72 case NodeListCollectionType: 73 73 break; 74 74 } … … 105 105 case DataListOptions: 106 106 case MapAreas: 107 case InvalidCollectionType:107 case NodeListCollectionType: 108 108 return NodeListIsRootedAtNode; 109 109 } … … 145 145 case FormControls: 146 146 return InvalidateForFormControls; 147 case InvalidCollectionType:147 case NodeListCollectionType: 148 148 break; 149 149 } … … 153 153 154 154 155 HTMLCollection::HTMLCollection(Node* base, CollectionType type, ItemBeforeSupportType itemBeforeSupportType) 156 : HTMLCollectionCacheBase(rootTypeFromCollectionType(type), invalidationTypeExcludingIdAndNameAttributes(type), type, itemBeforeSupportType) 157 , m_base(base) 158 { 159 ASSERT(m_base); 160 m_base->document()->registerNodeListCache(this); 155 HTMLCollection::HTMLCollection(Node* ownerNode, CollectionType type, ItemAfterOverrideType itemAfterOverrideType) 156 : HTMLCollectionCacheBase(ownerNode, rootTypeFromCollectionType(type), invalidationTypeExcludingIdAndNameAttributes(type), 157 WebCore::shouldOnlyIncludeDirectChildren(type), type, itemAfterOverrideType) 158 { 159 document()->registerNodeListCache(this); 161 160 } 162 161 163 162 PassRefPtr<HTMLCollection> HTMLCollection::create(Node* base, CollectionType type) 164 163 { 165 return adoptRef(new HTMLCollection(base, type, SupportItemBefore));164 return adoptRef(new HTMLCollection(base, type, DoesNotOverrideItemAfter)); 166 165 } 167 166 … … 177 176 ASSERT(type() == WindowNamedItems || type() == DocumentNamedItems); 178 177 179 m_base->document()->unregisterNodeListCache(this);178 document()->unregisterNodeListCache(this); 180 179 } 181 180 … … 232 231 case TableRows: 233 232 case WindowNamedItems: 234 case InvalidCollectionType:233 case NodeListCollectionType: 235 234 ASSERT_NOT_REACHED(); 236 235 } … … 255 254 } 256 255 257 template<bool forward> 258 static Element* itemBeforeOrAfter(CollectionType type, Node* base, unsigned& offsetInArray, Node* previous) 259 { 260 ASSERT_UNUSED(offsetInArray, !offsetInArray); 261 bool onlyIncludeDirectChildren = shouldOnlyIncludeDirectChildren(type); 262 Node* rootNode = base; 256 static Node* firstNode(bool forward, Node* rootNode, bool onlyIncludeDirectChildren) 257 { 258 if (forward) 259 return rootNode->firstChild(); 260 else 261 return onlyIncludeDirectChildren ? rootNode->lastChild() : lastDescendent(rootNode); 262 } 263 264 template <bool forward> 265 Node* DynamicNodeListCacheBase::iterateForNextNode(Node* current) const 266 { 267 bool onlyIncludeDirectChildren = shouldOnlyIncludeDirectChildren(); 268 CollectionType collectionType = type(); 269 Node* rootNode = this->rootNode(); 270 for (; current; current = nextNode<forward>(rootNode, current, onlyIncludeDirectChildren)) { 271 if (collectionType == NodeListCollectionType) { 272 if (current->isElementNode() && static_cast<const DynamicNodeList*>(this)->nodeMatches(toElement(current))) 273 return toElement(current); 274 } else { 275 if (current->isElementNode() && isAcceptableElement(collectionType, toElement(current))) 276 return toElement(current); 277 } 278 } 279 280 return 0; 281 } 282 283 // Without this ALWAYS_INLINE, length() and item() can be 100% slower. 284 template<bool forward> ALWAYS_INLINE 285 Node* DynamicNodeListCacheBase::itemBeforeOrAfter(Node* previous) const 286 { 263 287 Node* current; 264 if (previous) 265 current = nextNode<forward>(rootNode, previous, onlyIncludeDirectChildren); 266 else { 267 if (forward) 268 current = rootNode->firstChild(); 269 else 270 current = onlyIncludeDirectChildren ? rootNode->lastChild() : lastDescendent(rootNode); 271 } 272 273 for (; current; current = nextNode<forward>(rootNode, current, onlyIncludeDirectChildren)) { 274 if (current->isElementNode() && isAcceptableElement(type, toElement(current))) 275 return toElement(current); 276 } 277 278 return 0; 279 } 280 281 Element* HTMLCollection::itemBefore(unsigned& offsetInArray, Element* previous) const 282 { 283 return itemBeforeOrAfter<false>(type(), base(), offsetInArray, previous); 284 } 285 286 Element* HTMLCollection::itemAfter(unsigned& offsetInArray, Element* previous) const 287 { 288 return itemBeforeOrAfter<true>(type(), base(), offsetInArray, previous); 289 } 290 291 bool ALWAYS_INLINE HTMLCollection::isLastItemCloserThanLastOrCachedItem(unsigned offset) const 288 if (LIKELY(!!previous)) // Without this LIKELY, length() and item() can be 10% slower. 289 current = nextNode<forward>(rootNode(), previous, shouldOnlyIncludeDirectChildren()); 290 else 291 current = firstNode(forward, rootNode(), previous); 292 293 if (type() == NodeListCollectionType && shouldOnlyIncludeDirectChildren()) // ChildNodeList 294 return current; 295 296 return iterateForNextNode<forward>(current); 297 } 298 299 // Without this ALWAYS_INLINE, length() and item() can be 100% slower. 300 ALWAYS_INLINE Node* DynamicNodeListCacheBase::itemBefore(Node* previous) const 301 { 302 return itemBeforeOrAfter<false>(previous); 303 } 304 305 // Without this ALWAYS_INLINE, length() and item() can be 100% slower. 306 ALWAYS_INLINE Node* DynamicNodeListCacheBase::itemAfter(unsigned& offsetInArray, Node* previous) const 307 { 308 if (UNLIKELY(overridesItemAfter())) // Without this UNLIKELY, length() can be 100% slower. 309 return static_cast<const HTMLCollection*>(this)->virtualItemAfter(offsetInArray, toElement(previous)); 310 ASSERT(!offsetInArray); 311 return itemBeforeOrAfter<true>(previous); 312 } 313 314 bool ALWAYS_INLINE DynamicNodeListCacheBase::isLastItemCloserThanLastOrCachedItem(unsigned offset) const 292 315 { 293 316 ASSERT(isLengthCacheValid()); … … 299 322 } 300 323 301 bool ALWAYS_INLINE HTMLCollection::isFirstItemCloserThanCachedItem(unsigned offset) const324 bool ALWAYS_INLINE DynamicNodeListCacheBase::isFirstItemCloserThanCachedItem(unsigned offset) const 302 325 { 303 326 ASSERT(isItemCacheValid()); … … 309 332 } 310 333 311 unsigned HTMLCollection::length() const 334 ALWAYS_INLINE void DynamicNodeListCacheBase::setItemCache(Node* item, unsigned offset, unsigned elementsArrayOffset) const 335 { 336 setItemCache(item, offset); 337 if (overridesItemAfter()) { 338 ASSERT(item->isElementNode()); 339 static_cast<const HTMLCollectionCacheBase*>(this)->m_cachedElementsArrayOffset = elementsArrayOffset; 340 } else 341 ASSERT(!elementsArrayOffset); 342 } 343 344 ALWAYS_INLINE unsigned DynamicNodeListCacheBase::cachedElementsArrayOffset() const 345 { 346 return overridesItemAfter() ? static_cast<const HTMLCollectionCacheBase*>(this)->m_cachedElementsArrayOffset : 0; 347 } 348 349 unsigned DynamicNodeListCacheBase::lengthCommon() const 312 350 { 313 351 if (isLengthCacheValid()) 314 352 return cachedLength(); 315 353 316 if (!isItemCacheValid() && !item(0)) { 317 ASSERT(isLengthCacheValid()); 318 return 0; 319 } 320 321 ASSERT(isItemCacheValid()); 322 ASSERT(cachedItem()); 323 unsigned offset = cachedItemOffset(); 324 do { 325 offset++; 326 } while (itemBeforeOrAfterCachedItem(offset)); 354 itemCommon(UINT_MAX); 327 355 ASSERT(isLengthCacheValid()); 328 329 return offset;330 } 331 332 Node* HTMLCollection::item(unsigned offset) const356 357 return cachedLength(); 358 } 359 360 Node* DynamicNodeListCacheBase::itemCommon(unsigned offset) const 333 361 { 334 362 if (isItemCacheValid() && cachedItemOffset() == offset) … … 343 371 #endif 344 372 345 if (isLengthCacheValid() && supportsItemBefore() && isLastItemCloserThanLastOrCachedItem(offset)) { 346 // FIXME: Need to figure out the last offset in array for HTMLFormCollection and HTMLPropertiesCollection 347 unsigned unusedOffsetInArray = 0; 348 Node* lastItem = itemBefore(unusedOffsetInArray, 0); 349 ASSERT(!unusedOffsetInArray); 373 if (isLengthCacheValid() && !overridesItemAfter() && isLastItemCloserThanLastOrCachedItem(offset)) { 374 Node* lastItem = itemBefore(0); 350 375 ASSERT(lastItem); 351 376 setItemCache(lastItem, cachedLength() - 1, 0); 352 } else if (!isItemCacheValid() || isFirstItemCloserThanCachedItem(offset) || ( !supportsItemBefore() && offset < cachedItemOffset())) {377 } else if (!isItemCacheValid() || isFirstItemCloserThanCachedItem(offset) || (overridesItemAfter() && offset < cachedItemOffset())) { 353 378 unsigned offsetInArray = 0; 354 379 Node* firstItem = itemAfter(offsetInArray, 0); … … 367 392 } 368 393 369 Element* HTMLCollection::itemBeforeOrAfterCachedItem(unsigned offset) const394 Node* DynamicNodeListCacheBase::itemBeforeOrAfterCachedItem(unsigned offset) const 370 395 { 371 396 unsigned currentOffset = cachedItemOffset(); 372 ASSERT(cachedItem()->isElementNode()); 373 Element* currentItem = toElement(cachedItem()); 397 Node* currentItem = cachedItem(); 374 398 ASSERT(currentOffset != offset); 375 399 376 unsigned offsetInArray = cachedElementsArrayOffset();377 378 400 if (offset < cachedItemOffset()) { 379 ASSERT( supportsItemBefore());380 while ((currentItem = itemBefore( offsetInArray,currentItem))) {401 ASSERT(!overridesItemAfter()); 402 while ((currentItem = itemBefore(currentItem))) { 381 403 ASSERT(currentOffset); 382 404 currentOffset--; 383 405 if (currentOffset == offset) { 384 setItemCache(currentItem, currentOffset, offsetInArray);406 setItemCache(currentItem, currentOffset, 0); 385 407 return currentItem; 386 408 } … … 390 412 } 391 413 414 unsigned offsetInArray = cachedElementsArrayOffset(); 392 415 while ((currentItem = itemAfter(offsetInArray, currentItem))) { 393 416 currentOffset++; … … 401 424 setLengthCache(offsetOfLastItem + 1); 402 425 426 return 0; 427 } 428 429 Element* HTMLCollection::virtualItemAfter(unsigned&, Element*) const 430 { 431 ASSERT_NOT_REACHED(); 403 432 return 0; 404 433 } … … 442 471 unsigned arrayOffset = 0; 443 472 unsigned i = 0; 444 for ( Element* e = itemAfter(arrayOffset, 0); e; e = itemAfter(arrayOffset, e)) {445 if (checkForNameMatch( e, /* checkName */ false, name)) {473 for (Node* e = itemAfter(arrayOffset, 0); e; e = itemAfter(arrayOffset, e)) { 474 if (checkForNameMatch(toElement(e), /* checkName */ false, name)) { 446 475 setItemCache(e, i, arrayOffset); 447 476 return e; … … 451 480 452 481 i = 0; 453 for ( Element* e = itemAfter(arrayOffset, 0); e; e = itemAfter(arrayOffset, e)) {454 if (checkForNameMatch( e, /* checkName */ true, name)) {482 for (Node* e = itemAfter(arrayOffset, 0); e; e = itemAfter(arrayOffset, e)) { 483 if (checkForNameMatch(toElement(e), /* checkName */ true, name)) { 455 484 setItemCache(e, i, arrayOffset); 456 return e;485 return toElement(e); 457 486 } 458 487 i++; … … 468 497 469 498 unsigned arrayOffset = 0; 470 for ( Element* element = itemAfter(arrayOffset, 0); element; element = itemAfter(arrayOffset, element)) {471 if (! element->isHTMLElement())499 for (Node* node = itemAfter(arrayOffset, 0); node; node = itemAfter(arrayOffset, node)) { 500 if (!node->isHTMLElement()) 472 501 continue; 473 HTMLElement* e = toHTMLElement( element);502 HTMLElement* e = toHTMLElement(node); 474 503 const AtomicString& idAttrVal = e->getIdAttribute(); 475 504 const AtomicString& nameAttrVal = e->getNameAttribute(); … … 523 552 PassRefPtr<NodeList> HTMLCollection::tags(const String& name) 524 553 { 525 return m_base->getElementsByTagName(name);554 return ownerNode()->getElementsByTagName(name); 526 555 } 527 556 -
trunk/Source/WebCore/html/HTMLCollection.h
r122672 r123281 40 40 class HTMLCollectionCacheBase : public DynamicNodeListCacheBase { 41 41 public: 42 HTMLCollectionCacheBase(Node ListRootType rootType, NodeListInvalidationType invalidationType, CollectionType collectionType, ItemBeforeSupportType itemBeforeSupportType)43 : DynamicNodeListCacheBase(rootType, invalidationType, collectionType, itemBeforeSupportType)44 , m_cachedElementsArrayOffset(0)42 HTMLCollectionCacheBase(Node* ownerNode, NodeListRootType rootType, NodeListInvalidationType invalidationType, 43 bool shouldOnlyIncludeDirectChildren, CollectionType collectionType, ItemAfterOverrideType itemAfterOverrideType) 44 : DynamicNodeListCacheBase(ownerNode, rootType, invalidationType, shouldOnlyIncludeDirectChildren, collectionType, itemAfterOverrideType) 45 45 { 46 46 } 47 47 48 48 protected: 49 void setItemCache(Node* item, unsigned offset, unsigned elementsArrayOffset) const50 {51 setItemCache(item, offset);52 m_cachedElementsArrayOffset = elementsArrayOffset;53 }54 unsigned cachedElementsArrayOffset() const { return m_cachedElementsArrayOffset; }55 56 49 typedef HashMap<AtomicStringImpl*, OwnPtr<Vector<Element*> > > NodeCacheMap; 57 50 Vector<Element*>* idCache(const AtomicString& name) const { return m_idCache.get(name.impl()); } … … 64 57 private: 65 58 using DynamicNodeListCacheBase::isRootedAtDocument; 66 using DynamicNodeListCacheBase::setItemCache;67 59 68 60 mutable NodeCacheMap m_idCache; … … 70 62 mutable unsigned m_cachedElementsArrayOffset; 71 63 72 friend void DynamicNodeListCacheBase::invalidateCache() const;64 friend class DynamicNodeListCacheBase; 73 65 }; 74 66 … … 79 71 80 72 // DOM API 81 unsigned length() const ;82 Node* item(unsigned index) const;73 unsigned length() const { return lengthCommon(); } 74 Node* item(unsigned offset) const { return itemCommon(offset); } 83 75 virtual Node* namedItem(const AtomicString& name) const; 84 76 PassRefPtr<NodeList> tags(const String&); … … 104 96 } 105 97 106 Node* base() const { return m_base.get(); } 98 Node* base() const { return ownerNode(); } 99 virtual Element* virtualItemAfter(unsigned& offsetInArray, Element*) const; 107 100 108 101 protected: 109 HTMLCollection(Node* base, CollectionType, Item BeforeSupportType);102 HTMLCollection(Node* base, CollectionType, ItemAfterOverrideType); 110 103 111 104 virtual void updateNameCache() const; 112 virtual Element* itemAfter(unsigned& offsetInArray, Element*) const;113 105 114 106 private: 115 107 bool checkForNameMatch(Element*, bool checkName, const AtomicString& name) const; 116 117 Element* itemBefore(unsigned& offsetInArray, Element*) const;118 bool isLastItemCloserThanLastOrCachedItem(unsigned offset) const;119 bool isFirstItemCloserThanCachedItem(unsigned offset) const;120 Element* itemBeforeOrAfterCachedItem(unsigned offset) const;121 122 RefPtr<Node> m_base;123 108 }; 124 109 -
trunk/Source/WebCore/html/HTMLFormCollection.cpp
r122660 r123281 38 38 39 39 HTMLFormCollection::HTMLFormCollection(Element* base) 40 : HTMLCollection(base, FormControls, DoNotSupportItemBefore)40 : HTMLCollection(base, FormControls, OverridesItemAfter) 41 41 { 42 42 ASSERT(base->hasTagName(formTag) || base->hasTagName(fieldsetTag)); … … 68 68 } 69 69 70 Element* HTMLFormCollection:: itemAfter(unsigned& offset, Element* previousItem) const70 Element* HTMLFormCollection::virtualItemAfter(unsigned& offset, Element* previousItem) const 71 71 { 72 72 const Vector<FormAssociatedElement*>& elementsArray = formControlElements(); -
trunk/Source/WebCore/html/HTMLFormCollection.h
r122518 r123281 50 50 const Vector<FormAssociatedElement*>& formControlElements() const; 51 51 const Vector<HTMLImageElement*>& formImageElements() const; 52 virtual Element* itemAfter(unsigned& offsetInArray, Element*) const OVERRIDE;52 virtual Element* virtualItemAfter(unsigned& offsetInArray, Element*) const OVERRIDE; 53 53 }; 54 54 -
trunk/Source/WebCore/html/HTMLNameCollection.cpp
r122660 r123281 34 34 35 35 HTMLNameCollection::HTMLNameCollection(Document* document, CollectionType type, const AtomicString& name) 36 : HTMLCollection(document, type, DoNotSupportItemBefore)36 : HTMLCollection(document, type, OverridesItemAfter) 37 37 , m_name(name) 38 38 { … … 50 50 } 51 51 52 Element* HTMLNameCollection:: itemAfter(unsigned& offsetInArray, Element* previous) const52 Element* HTMLNameCollection::virtualItemAfter(unsigned& offsetInArray, Element* previous) const 53 53 { 54 54 ASSERT_UNUSED(offsetInArray, !offsetInArray); -
trunk/Source/WebCore/html/HTMLNameCollection.h
r122518 r123281 44 44 HTMLNameCollection(Document*, CollectionType, const AtomicString& name); 45 45 46 virtual Element* itemAfter(unsigned& offsetInArray, Element*) const OVERRIDE;46 virtual Element* virtualItemAfter(unsigned& offsetInArray, Element*) const OVERRIDE; 47 47 48 48 AtomicString m_name; -
trunk/Source/WebCore/html/HTMLOptionsCollection.cpp
r122660 r123281 29 29 30 30 HTMLOptionsCollection::HTMLOptionsCollection(Element* select) 31 : HTMLCollection(select, SelectOptions, SupportItemBefore)31 : HTMLCollection(select, SelectOptions, DoesNotOverrideItemAfter) 32 32 { 33 33 ASSERT(select->hasTagName(HTMLNames::selectTag)); -
trunk/Source/WebCore/html/HTMLPropertiesCollection.cpp
r122660 r123281 52 52 53 53 HTMLPropertiesCollection::HTMLPropertiesCollection(Node* itemNode) 54 : HTMLCollection(itemNode, ItemProperties, DoNotSupportItemBefore)54 : HTMLCollection(itemNode, ItemProperties, OverridesItemAfter) 55 55 , m_hasPropertyNameCache(false) 56 56 , m_hasItemRefElements(false) … … 113 113 } 114 114 115 Element* HTMLPropertiesCollection:: itemAfter(unsigned& offsetInArray, Element* previousItem) const115 Element* HTMLPropertiesCollection::virtualItemAfter(unsigned& offsetInArray, Element* previousItem) const 116 116 { 117 117 while (offsetInArray < m_itemRefElements.size()) { 118 if (Element* next = itemAfter(m_itemRefElements[offsetInArray], previousItem))118 if (Element* next = virtualItemAfter(m_itemRefElements[offsetInArray], previousItem)) 119 119 return next; 120 120 offsetInArray++; … … 124 124 } 125 125 126 HTMLElement* HTMLPropertiesCollection:: itemAfter(HTMLElement* base, Element* previous) const126 HTMLElement* HTMLPropertiesCollection::virtualItemAfter(HTMLElement* base, Element* previous) const 127 127 { 128 128 Node* current; … … 150 150 for (unsigned i = 0; i < m_itemRefElements.size(); ++i) { 151 151 HTMLElement* refElement = m_itemRefElements[i]; 152 for (HTMLElement* element = itemAfter(refElement, 0); element; element = itemAfter(refElement, element)) {152 for (HTMLElement* element = virtualItemAfter(refElement, 0); element; element = virtualItemAfter(refElement, element)) { 153 153 DOMSettableTokenList* itemProperty = element->itemProp(); 154 154 for (unsigned propertyIndex = 0; propertyIndex < itemProperty->length(); ++propertyIndex) -
trunk/Source/WebCore/html/HTMLPropertiesCollection.h
r122621 r123281 66 66 Node* findRefElements(Node* previous) const; 67 67 68 virtual Element* itemAfter(unsigned& offsetInArray, Element*) const OVERRIDE;69 HTMLElement* itemAfter(HTMLElement* base, Element* previous) const;68 virtual Element* virtualItemAfter(unsigned& offsetInArray, Element*) const OVERRIDE; 69 HTMLElement* virtualItemAfter(HTMLElement* base, Element* previous) const; 70 70 71 71 void updateNameCache() const; -
trunk/Source/WebCore/html/HTMLTableRowsCollection.cpp
r122660 r123281 153 153 // differ between compilers. 154 154 HTMLTableRowsCollection::HTMLTableRowsCollection(Element* table) 155 : HTMLCollection(table, TableRows, DoNotSupportItemBefore)155 : HTMLCollection(table, TableRows, OverridesItemAfter) 156 156 { 157 157 ASSERT(table->hasTagName(tableTag)); … … 163 163 } 164 164 165 Element* HTMLTableRowsCollection:: itemAfter(unsigned& offsetInArray, Element* previous) const165 Element* HTMLTableRowsCollection::virtualItemAfter(unsigned& offsetInArray, Element* previous) const 166 166 { 167 167 ASSERT_UNUSED(offsetInArray, !offsetInArray); -
trunk/Source/WebCore/html/HTMLTableRowsCollection.h
r122518 r123281 47 47 HTMLTableRowsCollection(Element*); 48 48 49 virtual Element* itemAfter(unsigned& offsetInArray, Element*) const OVERRIDE;49 virtual Element* virtualItemAfter(unsigned& offsetInArray, Element*) const OVERRIDE; 50 50 }; 51 51 -
trunk/Source/WebCore/html/LabelsNodeList.cpp
r122498 r123281 35 35 36 36 LabelsNodeList::LabelsNodeList(Node* forNode) 37 : DynamicSubtreeNodeList(forNode, InvalidateOnForAttrChange, NodeListIsRootedAtDocument)37 : DynamicSubtreeNodeList(forNode, LabelsNodeListType, InvalidateOnForAttrChange, NodeListIsRootedAtDocument) 38 38 { 39 39 } -
trunk/Source/WebCore/html/RadioNodeList.cpp
r122546 r123281 39 39 40 40 RadioNodeList::RadioNodeList(Node* rootNode, const AtomicString& name) 41 : DynamicSubtreeNodeList(rootNode, InvalidateForFormControls, rootNode->hasTagName(formTag) ? NodeListIsRootedAtDocument : NodeListIsRootedAtNode)41 : DynamicSubtreeNodeList(rootNode, RadioNodeListType, InvalidateForFormControls, rootNode->hasTagName(formTag) ? NodeListIsRootedAtDocument : NodeListIsRootedAtNode) 42 42 , m_name(name) 43 43 {
Note: See TracChangeset
for help on using the changeset viewer.