Home | History | Annotate | Download | only in html
      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/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
     50     unsigned length() const { return m_collectionIndexCache.nodeCount(*this); }
     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;
     58     bool isEmpty() const { return m_collectionIndexCache.isEmpty(*this); }
     59     bool hasExactlyOneItem() const { return m_collectionIndexCache.hasExactlyOneNode(*this); }
     60 
     61     // CollectionIndexCache API.
     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:
     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             visitor->trace(m_idCache);
     88             visitor->trace(m_nameCache);
     89         }
     90 
     91     private:
     92         NamedItemCache();
     93         typedef WillBeHeapHashMap<StringImpl*, OwnPtrWillBeMember<WillBeHeapVector<RawPtrWillBeMember<Element> > > > StringToElementsMap;
     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 
    106     bool overridesItemAfter() const { return m_overridesItemAfter; }
    107     virtual Element* virtualItemAfter(Element*) const;
    108     bool shouldOnlyIncludeDirectChildren() const { return m_shouldOnlyIncludeDirectChildren; }
    109     virtual void supportedPropertyNames(Vector<String>& names);
    110 
    111     virtual void updateIdNameCache() const;
    112     bool hasValidIdNameCache() const { return m_namedItemCache; }
    113 
    114     void setNamedItemCache(PassOwnPtrWillBeRawPtr<NamedItemCache> cache) const
    115     {
    116         ASSERT(!m_namedItemCache);
    117         document().registerNodeListWithIdNameCache(this);
    118         m_namedItemCache = cache;
    119     }
    120 
    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 
    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 
    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