Home | History | Annotate | Download | only in dom
      1 /*
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 1999 Antti Koivisto (koivisto (at) kde.org)
      4  *           (C) 2001 Dirk Mueller (mueller (at) kde.org)
      5  * Copyright (C) 2004, 2006, 2007 Apple Inc. 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 LiveNodeList_h
     25 #define LiveNodeList_h
     26 
     27 #include "HTMLNames.h"
     28 #include "core/dom/Document.h"
     29 #include "core/dom/NodeList.h"
     30 #include "core/html/CollectionType.h"
     31 #include "wtf/Forward.h"
     32 #include "wtf/RefPtr.h"
     33 
     34 namespace WebCore {
     35 
     36 class Element;
     37 
     38 enum NodeListRootType {
     39     NodeListIsRootedAtNode,
     40     NodeListIsRootedAtDocument,
     41     NodeListIsRootedAtDocumentIfOwnerHasItemrefAttr,
     42 };
     43 
     44 class LiveNodeListBase : public NodeList {
     45 public:
     46     enum ItemAfterOverrideType {
     47         OverridesItemAfter,
     48         DoesNotOverrideItemAfter,
     49     };
     50 
     51     LiveNodeListBase(Node* ownerNode, NodeListRootType rootType, NodeListInvalidationType invalidationType,
     52         bool shouldOnlyIncludeDirectChildren, CollectionType collectionType, ItemAfterOverrideType itemAfterOverrideType)
     53         : m_ownerNode(ownerNode)
     54         , m_cachedItem(0)
     55         , m_isLengthCacheValid(false)
     56         , m_isItemCacheValid(false)
     57         , m_rootType(rootType)
     58         , m_invalidationType(invalidationType)
     59         , m_shouldOnlyIncludeDirectChildren(shouldOnlyIncludeDirectChildren)
     60         , m_isNameCacheValid(false)
     61         , m_collectionType(collectionType)
     62         , m_overridesItemAfter(itemAfterOverrideType == OverridesItemAfter)
     63         , m_isItemRefElementsCacheValid(false)
     64     {
     65         ASSERT(m_rootType == static_cast<unsigned>(rootType));
     66         ASSERT(m_invalidationType == static_cast<unsigned>(invalidationType));
     67         ASSERT(m_collectionType == static_cast<unsigned>(collectionType));
     68         ASSERT(!m_overridesItemAfter || !isNodeList(collectionType));
     69 
     70         if (collectionType != ChildNodeListType)
     71             document().registerNodeList(this);
     72     }
     73 
     74     virtual ~LiveNodeListBase()
     75     {
     76         if (type() != ChildNodeListType)
     77             document().unregisterNodeList(this);
     78     }
     79 
     80     // DOM API
     81     virtual unsigned length() const OVERRIDE;
     82     virtual Node* item(unsigned offset) const OVERRIDE;
     83 
     84     ALWAYS_INLINE bool hasIdNameCache() const { return !isNodeList(type()); }
     85     ALWAYS_INLINE bool isRootedAtDocument() const { return m_rootType == NodeListIsRootedAtDocument || m_rootType == NodeListIsRootedAtDocumentIfOwnerHasItemrefAttr; }
     86     ALWAYS_INLINE NodeListInvalidationType invalidationType() const { return static_cast<NodeListInvalidationType>(m_invalidationType); }
     87     ALWAYS_INLINE CollectionType type() const { return static_cast<CollectionType>(m_collectionType); }
     88     Node* ownerNode() const { return m_ownerNode.get(); }
     89     ALWAYS_INLINE void invalidateCache(const QualifiedName* attrName) const
     90     {
     91         if (!attrName || shouldInvalidateTypeOnAttributeChange(invalidationType(), *attrName))
     92             invalidateCache();
     93         else if (hasIdNameCache() && (*attrName == HTMLNames::idAttr || *attrName == HTMLNames::nameAttr))
     94             invalidateIdNameCacheMaps();
     95     }
     96     void invalidateCache() const;
     97     void invalidateIdNameCacheMaps() const;
     98 
     99     static bool shouldInvalidateTypeOnAttributeChange(NodeListInvalidationType, const QualifiedName&);
    100 
    101 protected:
    102     Document& document() const { return m_ownerNode->document(); }
    103     Node& rootNode() const;
    104     ContainerNode* rootContainerNode() const;
    105     bool overridesItemAfter() const { return m_overridesItemAfter; }
    106 
    107     ALWAYS_INLINE bool isItemCacheValid() const { return m_isItemCacheValid; }
    108     ALWAYS_INLINE Node* cachedItem() const { return m_cachedItem; }
    109     ALWAYS_INLINE unsigned cachedItemOffset() const { return m_cachedItemOffset; }
    110 
    111     ALWAYS_INLINE bool isLengthCacheValid() const { return m_isLengthCacheValid; }
    112     ALWAYS_INLINE unsigned cachedLength() const { return m_cachedLength; }
    113     ALWAYS_INLINE void setLengthCache(unsigned length) const
    114     {
    115         m_cachedLength = length;
    116         m_isLengthCacheValid = true;
    117     }
    118     ALWAYS_INLINE void setItemCache(Node* item, unsigned offset) const
    119     {
    120         ASSERT(item);
    121         m_cachedItem = item;
    122         m_cachedItemOffset = offset;
    123         m_isItemCacheValid = true;
    124     }
    125     void setItemCache(Node* item, unsigned offset, unsigned elementsArrayOffset) const;
    126 
    127     ALWAYS_INLINE bool isItemRefElementsCacheValid() const { return m_isItemRefElementsCacheValid; }
    128     ALWAYS_INLINE void setItemRefElementsCacheValid() const { m_isItemRefElementsCacheValid = true; }
    129 
    130     ALWAYS_INLINE NodeListRootType rootType() const { return static_cast<NodeListRootType>(m_rootType); }
    131 
    132     bool hasNameCache() const { return m_isNameCacheValid; }
    133     void setHasNameCache() const { m_isNameCacheValid = true; }
    134 
    135     bool shouldOnlyIncludeDirectChildren() const { return m_shouldOnlyIncludeDirectChildren; }
    136 
    137 private:
    138     Node* itemBeforeOrAfterCachedItem(unsigned offset, ContainerNode* root) const;
    139     Node* traverseChildNodeListForwardToOffset(unsigned offset, Node* currentNode, unsigned& currentOffset) const;
    140     Element* traverseLiveNodeListFirstElement(ContainerNode& root) const;
    141     Element* traverseLiveNodeListForwardToOffset(unsigned offset, Element& currentElement, unsigned& currentOffset, ContainerNode* root) const;
    142     bool isLastItemCloserThanLastOrCachedItem(unsigned offset) const;
    143     bool isFirstItemCloserThanCachedItem(unsigned offset) const;
    144     Node* iterateForPreviousNode(Node* current) const;
    145     Node* itemBefore(Node* previousItem) const;
    146 
    147     RefPtr<Node> m_ownerNode;
    148     mutable Node* m_cachedItem;
    149     mutable unsigned m_cachedLength;
    150     mutable unsigned m_cachedItemOffset;
    151     mutable unsigned m_isLengthCacheValid : 1;
    152     mutable unsigned m_isItemCacheValid : 1;
    153     const unsigned m_rootType : 2;
    154     const unsigned m_invalidationType : 4;
    155     const unsigned m_shouldOnlyIncludeDirectChildren : 1;
    156 
    157     // From HTMLCollection
    158     mutable unsigned m_isNameCacheValid : 1;
    159     const unsigned m_collectionType : 5;
    160     const unsigned m_overridesItemAfter : 1;
    161     mutable unsigned m_isItemRefElementsCacheValid : 1;
    162 };
    163 
    164 ALWAYS_INLINE bool LiveNodeListBase::shouldInvalidateTypeOnAttributeChange(NodeListInvalidationType type, const QualifiedName& attrName)
    165 {
    166     switch (type) {
    167     case InvalidateOnClassAttrChange:
    168         return attrName == HTMLNames::classAttr;
    169     case InvalidateOnNameAttrChange:
    170         return attrName == HTMLNames::nameAttr;
    171     case InvalidateOnIdNameAttrChange:
    172         return attrName == HTMLNames::idAttr || attrName == HTMLNames::nameAttr;
    173     case InvalidateOnForAttrChange:
    174         return attrName == HTMLNames::forAttr;
    175     case InvalidateForFormControls:
    176         return attrName == HTMLNames::nameAttr || attrName == HTMLNames::idAttr || attrName == HTMLNames::forAttr
    177             || attrName == HTMLNames::formAttr || attrName == HTMLNames::typeAttr;
    178     case InvalidateOnHRefAttrChange:
    179         return attrName == HTMLNames::hrefAttr;
    180     case InvalidateOnItemAttrChange:
    181     case DoNotInvalidateOnAttributeChanges:
    182         return false;
    183     case InvalidateOnAnyAttrChange:
    184         return true;
    185     }
    186     return false;
    187 }
    188 
    189 class LiveNodeList : public LiveNodeListBase {
    190 public:
    191     LiveNodeList(PassRefPtr<Node> ownerNode, CollectionType collectionType, NodeListInvalidationType invalidationType, NodeListRootType rootType = NodeListIsRootedAtNode)
    192         : LiveNodeListBase(ownerNode.get(), rootType, invalidationType, collectionType == ChildNodeListType,
    193         collectionType, DoesNotOverrideItemAfter)
    194     { }
    195 
    196     virtual Node* namedItem(const AtomicString&) const OVERRIDE;
    197     virtual bool nodeMatches(Element*) const = 0;
    198 
    199 private:
    200     virtual bool isLiveNodeList() const OVERRIDE { return true; }
    201 };
    202 
    203 } // namespace WebCore
    204 
    205 #endif // LiveNodeList_h
    206