Avoid unnecessary HTML Collection invalidations for id and name attribute changes
[WebKit-https.git] / Source / WebCore / html / HTMLCollection.h
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2011, 2012 Apple Inc. All rights reserved.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  */
22
23 #ifndef HTMLCollection_h
24 #define HTMLCollection_h
25
26 #include "CollectionIndexCache.h"
27 #include "CollectionType.h"
28 #include "ContainerNode.h"
29 #include "Document.h"
30 #include "HTMLNames.h"
31 #include "LiveNodeList.h"
32 #include "ScriptWrappable.h"
33 #include <wtf/Forward.h>
34 #include <wtf/HashMap.h>
35 #include <wtf/Vector.h>
36
37 namespace WebCore {
38
39 class Element;
40
41 class HTMLCollection : public ScriptWrappable, public RefCounted<HTMLCollection> {
42 public:
43     static PassRefPtr<HTMLCollection> create(ContainerNode& base, CollectionType);
44     virtual ~HTMLCollection();
45
46     // DOM API
47     unsigned length() const;
48     Node* item(unsigned offset) const;
49     virtual Node* namedItem(const AtomicString& name) const;
50     PassRefPtr<NodeList> tags(const String&);
51
52     // Non-DOM API
53     bool hasNamedItem(const AtomicString& name) const;
54     void namedItems(const AtomicString& name, Vector<Ref<Element>>&) const;
55
56     bool isRootedAtDocument() const { return m_rootType == NodeListIsRootedAtDocument; }
57     NodeListInvalidationType invalidationType() const { return static_cast<NodeListInvalidationType>(m_invalidationType); }
58     CollectionType type() const { return static_cast<CollectionType>(m_collectionType); }
59     ContainerNode& ownerNode() const { return const_cast<ContainerNode&>(m_ownerNode.get()); }
60     void invalidateCache(const QualifiedName* attrName) const
61     {
62         if (!attrName || shouldInvalidateTypeOnAttributeChange(invalidationType(), *attrName))
63             invalidateCache();
64         else if (hasIdNameCache() && (*attrName == HTMLNames::idAttr || *attrName == HTMLNames::nameAttr))
65             invalidateIdNameCacheMaps();
66     }
67     virtual void invalidateCache() const;
68
69     // For CollectionIndexCache
70     Element* collectionFirst() const;
71     Element* collectionLast() const;
72     Element* collectionTraverseForward(Element&, unsigned count, unsigned& traversedCount) const;
73     Element* collectionTraverseBackward(Element&, unsigned count) const;
74     bool collectionCanTraverseBackward() const { return !m_usesCustomForwardOnlyTraversal; }
75
76     bool hasIdNameCache() const { return m_isNameCacheValid; }
77
78 protected:
79     enum ElementTraversalType { NormalTraversal, CustomForwardOnlyTraversal };
80     HTMLCollection(ContainerNode& base, CollectionType, ElementTraversalType = NormalTraversal);
81
82     void invalidateIdNameCacheMaps() const;
83     virtual void updateNameCache() const;
84
85     typedef HashMap<AtomicStringImpl*, OwnPtr<Vector<Element*>>> NodeCacheMap;
86     Vector<Element*>* idCache(const AtomicString& name) const { return m_idCache.get(name.impl()); }
87     Vector<Element*>* nameCache(const AtomicString& name) const { return m_nameCache.get(name.impl()); }
88     void appendIdCache(const AtomicString& name, Element* element) const { append(m_idCache, name, element); }
89     void appendNameCache(const AtomicString& name, Element* element) const { append(m_nameCache, name, element); }
90
91     Document& document() const { return m_ownerNode->document(); }
92     ContainerNode& rootNode() const;
93     bool usesCustomForwardOnlyTraversal() const { return m_usesCustomForwardOnlyTraversal; }
94
95     bool isItemRefElementsCacheValid() const { return m_isItemRefElementsCacheValid; }
96     void setItemRefElementsCacheValid() const { m_isItemRefElementsCacheValid = true; }
97
98     NodeListRootType rootType() const { return static_cast<NodeListRootType>(m_rootType); }
99
100     void setHasIdNameCache() const
101     {
102         m_isNameCacheValid = true;
103         document().collectionCachedIdNameMap(*this);
104     }
105
106 private:
107     static void append(NodeCacheMap&, const AtomicString&, Element*);
108
109     Element* iterateForPreviousElement(Element* current) const;
110     Element* firstElement(ContainerNode& root) const;
111     Element* traverseForward(Element& current, unsigned count, unsigned& traversedCount, ContainerNode& root) const;
112
113     virtual Element* customElementAfter(Element*) const { ASSERT_NOT_REACHED(); return nullptr; }
114
115     Ref<ContainerNode> m_ownerNode;
116
117     mutable CollectionIndexCache<HTMLCollection, Element> m_indexCache;
118
119     const unsigned m_rootType : 1;
120     const unsigned m_invalidationType : 4;
121     const unsigned m_shouldOnlyIncludeDirectChildren : 1;
122
123     mutable unsigned m_isNameCacheValid : 1;
124     const unsigned m_collectionType : 5;
125     const unsigned m_usesCustomForwardOnlyTraversal : 1;
126     mutable unsigned m_isItemRefElementsCacheValid : 1;
127
128     mutable NodeCacheMap m_idCache;
129     mutable NodeCacheMap m_nameCache;
130 };
131
132 } // namespace
133
134 #endif