• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * Copyright (C) 2014 Samsung Electronics. 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 HTMLCollection_h
25 #define HTMLCollection_h
26 
27 #include "core/dom/LiveNodeListBase.h"
28 #include "core/html/CollectionIndexCache.h"
29 #include "core/html/CollectionType.h"
30 #include "wtf/Forward.h"
31 #include "wtf/HashMap.h"
32 #include "wtf/Vector.h"
33 
34 namespace WebCore {
35 
36 class HTMLCollection : public RefCountedWillBeGarbageCollectedFinalized<HTMLCollection>, public ScriptWrappable, public LiveNodeListBase {
37     WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(HTMLCollection);
38 public:
39     enum ItemAfterOverrideType {
40         OverridesItemAfter,
41         DoesNotOverrideItemAfter,
42     };
43 
44     static PassRefPtrWillBeRawPtr<HTMLCollection> create(ContainerNode& base, CollectionType);
45     virtual ~HTMLCollection();
46     virtual void invalidateCache(Document* oldDocument = 0) const OVERRIDE;
47     void invalidateCacheForAttribute(const QualifiedName*) const;
48 
49     // DOM API
length()50     unsigned length() const { return m_collectionIndexCache.nodeCount(*this); }
item(unsigned offset)51     Element* item(unsigned offset) const { return m_collectionIndexCache.nodeAt(*this, offset); }
52     virtual Element* namedItem(const AtomicString& name) const;
53     bool namedPropertyQuery(const AtomicString&, ExceptionState&);
54     void namedPropertyEnumerator(Vector<String>& names, ExceptionState&);
55 
56     // Non-DOM API
57     void namedItems(const AtomicString& name, WillBeHeapVector<RefPtrWillBeMember<Element> >&) const;
isEmpty()58     bool isEmpty() const { return m_collectionIndexCache.isEmpty(*this); }
hasExactlyOneItem()59     bool hasExactlyOneItem() const { return m_collectionIndexCache.hasExactlyOneNode(*this); }
60 
61     // CollectionIndexCache API.
canTraverseBackward()62     bool canTraverseBackward() const { return !overridesItemAfter(); }
63     Element* traverseToFirstElement() const;
64     Element* traverseToLastElement() const;
65     Element* traverseForwardToOffset(unsigned offset, Element& currentElement, unsigned& currentOffset) const;
66     Element* traverseBackwardToOffset(unsigned offset, Element& currentElement, unsigned& currentOffset) const;
67 
68     virtual void trace(Visitor*);
69 
70 protected:
71     HTMLCollection(ContainerNode& base, CollectionType, ItemAfterOverrideType);
72 
73     class NamedItemCache FINAL : public NoBaseWillBeGarbageCollected<NamedItemCache> {
74     public:
create()75         static PassOwnPtrWillBeRawPtr<NamedItemCache> create()
76         {
77             return adoptPtrWillBeNoop(new NamedItemCache);
78         }
79 
getElementsById(const AtomicString & id)80         WillBeHeapVector<RawPtrWillBeMember<Element> >* getElementsById(const AtomicString& id) const { return m_idCache.get(id.impl()); }
getElementsByName(const AtomicString & name)81         WillBeHeapVector<RawPtrWillBeMember<Element> >* getElementsByName(const AtomicString& name) const { return m_nameCache.get(name.impl()); }
addElementWithId(const AtomicString & id,Element * element)82         void addElementWithId(const AtomicString& id, Element* element) { addElementToMap(m_idCache, id, element); }
addElementWithName(const AtomicString & name,Element * element)83         void addElementWithName(const AtomicString& name, Element* element) { addElementToMap(m_nameCache, name, element); }
84 
trace(Visitor * visitor)85         void trace(Visitor* visitor)
86         {
87             visitor->trace(m_idCache);
88             visitor->trace(m_nameCache);
89         }
90 
91     private:
92         NamedItemCache();
93         typedef WillBeHeapHashMap<StringImpl*, OwnPtrWillBeMember<WillBeHeapVector<RawPtrWillBeMember<Element> > > > StringToElementsMap;
addElementToMap(StringToElementsMap & map,const AtomicString & key,Element * element)94         static void addElementToMap(StringToElementsMap& map, const AtomicString& key, Element* element)
95         {
96             OwnPtrWillBeMember<WillBeHeapVector<RawPtrWillBeMember<Element> > >& vector = map.add(key.impl(), nullptr).storedValue->value;
97             if (!vector)
98                 vector = adoptPtrWillBeNoop(new WillBeHeapVector<RawPtrWillBeMember<Element> >);
99             vector->append(element);
100         }
101 
102         StringToElementsMap m_idCache;
103         StringToElementsMap m_nameCache;
104     };
105 
overridesItemAfter()106     bool overridesItemAfter() const { return m_overridesItemAfter; }
107     virtual Element* virtualItemAfter(Element*) const;
shouldOnlyIncludeDirectChildren()108     bool shouldOnlyIncludeDirectChildren() const { return m_shouldOnlyIncludeDirectChildren; }
109     virtual void supportedPropertyNames(Vector<String>& names);
110 
111     virtual void updateIdNameCache() const;
hasValidIdNameCache()112     bool hasValidIdNameCache() const { return m_namedItemCache; }
113 
setNamedItemCache(PassOwnPtrWillBeRawPtr<NamedItemCache> cache)114     void setNamedItemCache(PassOwnPtrWillBeRawPtr<NamedItemCache> cache) const
115     {
116         ASSERT(!m_namedItemCache);
117         document().registerNodeListWithIdNameCache(this);
118         m_namedItemCache = cache;
119     }
120 
namedItemCache()121     NamedItemCache& namedItemCache() const
122     {
123         ASSERT(m_namedItemCache);
124         return *m_namedItemCache;
125     }
126 
127 private:
128     void invalidateIdNameCacheMaps(Document* oldDocument = 0) const
129     {
130         if (!hasValidIdNameCache())
131             return;
132 
133         // Make sure we decrement the NodeListWithIdNameCache count from
134         // the old document instead of the new one in the case the collection
135         // is moved to a new document.
136         unregisterIdNameCacheFromDocument(oldDocument ? *oldDocument : document());
137 
138         m_namedItemCache.clear();
139     }
140 
unregisterIdNameCacheFromDocument(Document & document)141     void unregisterIdNameCacheFromDocument(Document& document) const
142     {
143         ASSERT(hasValidIdNameCache());
144         document.unregisterNodeListWithIdNameCache(this);
145     }
146 
147     const unsigned m_overridesItemAfter : 1;
148     const unsigned m_shouldOnlyIncludeDirectChildren : 1;
149     mutable OwnPtrWillBeMember<NamedItemCache> m_namedItemCache;
150     mutable CollectionIndexCache<HTMLCollection, Element> m_collectionIndexCache;
151 };
152 
153 DEFINE_TYPE_CASTS(HTMLCollection, LiveNodeListBase, collection, isHTMLCollectionType(collection->type()), isHTMLCollectionType(collection.type()));
154 
invalidateCacheForAttribute(const QualifiedName * attrName)155 inline void HTMLCollection::invalidateCacheForAttribute(const QualifiedName* attrName) const
156 {
157     if (!attrName || shouldInvalidateTypeOnAttributeChange(invalidationType(), *attrName))
158         invalidateCache();
159     else if (*attrName == HTMLNames::idAttr || *attrName == HTMLNames::nameAttr)
160         invalidateIdNameCacheMaps();
161 }
162 
163 } // namespace
164 
165 #endif
166