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