Changeset 166369 in webkit


Ignore:
Timestamp:
Mar 27, 2014, 1:49:27 PM (12 years ago)
Author:
Antti Koivisto
Message:

Remove some unnecessary branches from LiveNodeList traversal
https://bugs.webkit.org/show_bug.cgi?id=130854

Reviewed by Andreas Kling.

Compile different traversal code paths for all NodeList subclasses.

  • dom/ClassNodeList.cpp:

(WebCore::ClassNodeList::ClassNodeList):
(WebCore::ClassNodeList::~ClassNodeList):
(WebCore::ClassNodeList::nodeMatches): Deleted.

  • dom/ClassNodeList.h:

(WebCore::ClassNodeList::nodeMatches):
(WebCore::ClassNodeList::nodeMatchesInlined): Deleted.

Remove separate nodeMatchesInlined functions.
We now rely on exact types and marking classes final.

  • dom/LiveNodeList.cpp:

(WebCore::LiveNodeList::LiveNodeList):
(WebCore::LiveNodeList::~LiveNodeList):
(WebCore::LiveNodeList::namedItem):
(WebCore::LiveNodeList::rootNode): Deleted.
(WebCore::isMatchingElement): Deleted.
(WebCore::firstMatchingElement): Deleted.
(WebCore::lastMatchingElement): Deleted.
(WebCore::nextMatchingElement): Deleted.
(WebCore::previousMatchingElement): Deleted.
(WebCore::traverseMatchingElementsForward): Deleted.
(WebCore::traverseMatchingElementsBackward): Deleted.
(WebCore::LiveNodeList::collectionFirst): Deleted.
(WebCore::LiveNodeList::collectionLast): Deleted.
(WebCore::LiveNodeList::collectionTraverseForward): Deleted.
(WebCore::LiveNodeList::collectionTraverseBackward): Deleted.
(WebCore::LiveNodeList::length): Deleted.
(WebCore::LiveNodeList::item): Deleted.
(WebCore::LiveNodeList::memoryCost): Deleted.
(WebCore::LiveNodeList::invalidateCache): Deleted.

  • dom/LiveNodeList.h:

(WebCore::LiveNodeList::invalidateCacheForAttribute):
(WebCore::CachedLiveNodeList::collectionCanTraverseBackward):
(WebCore::LiveNodeList::rootNode):
(WebCore::CachedLiveNodeList<NodeListType>::CachedLiveNodeList):

Add CachedLiveNodeList<NodeListType> utility type that interfaces with CollectionIndexCache.
It is the base class for all concrete LiveNodeLists.

(WebCore::CachedLiveNodeList<NodeListType>::~CachedLiveNodeList):
(WebCore::CachedLiveNodeList<NodeListType>::collectionFirst):
(WebCore::CachedLiveNodeList<NodeListType>::collectionLast):
(WebCore::nextMatchingElement):
(WebCore::CachedLiveNodeList<NodeListType>::collectionTraverseForward):
(WebCore::previousMatchingElement):
(WebCore::CachedLiveNodeList<NodeListType>::collectionTraverseBackward):
(WebCore::CachedLiveNodeList<NodeListType>::willValidateIndexCache):
(WebCore::CachedLiveNodeList<NodeListType>::invalidateCache):
(WebCore::CachedLiveNodeList<NodeListType>::length):
(WebCore::CachedLiveNodeList<NodeListType>::item):
(WebCore::CachedLiveNodeList<NodeListType>::memoryCost):

Templated code moves to header.

(WebCore::LiveNodeList::LiveNodeList): Deleted.
(WebCore::LiveNodeList::~LiveNodeList): Deleted.
(WebCore::LiveNodeList::invalidateCache): Deleted.
(WebCore::LiveNodeList::collectionCanTraverseBackward): Deleted.
(WebCore::LiveNodeList::willValidateIndexCache): Deleted.

  • dom/NameNodeList.cpp:

(WebCore::NameNodeList::NameNodeList):

  • dom/NameNodeList.h:
  • dom/Node.cpp:

(WebCore::Document::invalidateNodeListAndCollectionCaches):
(WebCore::NodeListsNodeData::invalidateCaches):

  • dom/TagNodeList.cpp:

(WebCore::TagNodeList::TagNodeList):
(WebCore::HTMLTagNodeList::HTMLTagNodeList):
(WebCore::HTMLTagNodeList::~HTMLTagNodeList):
(WebCore::TagNodeList::nodeMatches): Deleted.
(WebCore::HTMLTagNodeList::nodeMatches): Deleted.

  • dom/TagNodeList.h:

(WebCore::TagNodeList::nodeMatches):
(WebCore::HTMLTagNodeList::nodeMatches):
(WebCore::TagNodeList::create): Deleted.
(WebCore::HTMLTagNodeList::nodeMatchesInlined): Deleted.

  • html/LabelsNodeList.cpp:

(WebCore::LabelsNodeList::LabelsNodeList):

  • html/LabelsNodeList.h:
  • html/RadioNodeList.cpp:

(WebCore::RadioNodeList::RadioNodeList):

  • html/RadioNodeList.h:
Location:
trunk/Source/WebCore
Files:
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r166368 r166369  
     12014-03-27  Antti Koivisto  <antti@apple.com>
     2
     3        Remove some unnecessary branches from LiveNodeList traversal
     4        https://bugs.webkit.org/show_bug.cgi?id=130854
     5
     6        Reviewed by Andreas Kling.
     7
     8        Compile different traversal code paths for all NodeList subclasses.
     9
     10        * dom/ClassNodeList.cpp:
     11        (WebCore::ClassNodeList::ClassNodeList):
     12        (WebCore::ClassNodeList::~ClassNodeList):
     13        (WebCore::ClassNodeList::nodeMatches): Deleted.
     14        * dom/ClassNodeList.h:
     15        (WebCore::ClassNodeList::nodeMatches):
     16        (WebCore::ClassNodeList::nodeMatchesInlined): Deleted.
     17       
     18            Remove separate nodeMatchesInlined functions.
     19            We now rely on exact types and marking classes final.
     20
     21        * dom/LiveNodeList.cpp:
     22        (WebCore::LiveNodeList::LiveNodeList):
     23        (WebCore::LiveNodeList::~LiveNodeList):
     24        (WebCore::LiveNodeList::namedItem):
     25        (WebCore::LiveNodeList::rootNode): Deleted.
     26        (WebCore::isMatchingElement): Deleted.
     27        (WebCore::firstMatchingElement): Deleted.
     28        (WebCore::lastMatchingElement): Deleted.
     29        (WebCore::nextMatchingElement): Deleted.
     30        (WebCore::previousMatchingElement): Deleted.
     31        (WebCore::traverseMatchingElementsForward): Deleted.
     32        (WebCore::traverseMatchingElementsBackward): Deleted.
     33        (WebCore::LiveNodeList::collectionFirst): Deleted.
     34        (WebCore::LiveNodeList::collectionLast): Deleted.
     35        (WebCore::LiveNodeList::collectionTraverseForward): Deleted.
     36        (WebCore::LiveNodeList::collectionTraverseBackward): Deleted.
     37        (WebCore::LiveNodeList::length): Deleted.
     38        (WebCore::LiveNodeList::item): Deleted.
     39        (WebCore::LiveNodeList::memoryCost): Deleted.
     40        (WebCore::LiveNodeList::invalidateCache): Deleted.
     41        * dom/LiveNodeList.h:
     42        (WebCore::LiveNodeList::invalidateCacheForAttribute):
     43        (WebCore::CachedLiveNodeList::collectionCanTraverseBackward):
     44        (WebCore::LiveNodeList::rootNode):
     45        (WebCore::CachedLiveNodeList<NodeListType>::CachedLiveNodeList):
     46       
     47            Add CachedLiveNodeList<NodeListType> utility type that interfaces with CollectionIndexCache.
     48            It is the base class for all concrete LiveNodeLists.
     49
     50        (WebCore::CachedLiveNodeList<NodeListType>::~CachedLiveNodeList):
     51        (WebCore::CachedLiveNodeList<NodeListType>::collectionFirst):
     52        (WebCore::CachedLiveNodeList<NodeListType>::collectionLast):
     53        (WebCore::nextMatchingElement):
     54        (WebCore::CachedLiveNodeList<NodeListType>::collectionTraverseForward):
     55        (WebCore::previousMatchingElement):
     56        (WebCore::CachedLiveNodeList<NodeListType>::collectionTraverseBackward):
     57        (WebCore::CachedLiveNodeList<NodeListType>::willValidateIndexCache):
     58        (WebCore::CachedLiveNodeList<NodeListType>::invalidateCache):
     59        (WebCore::CachedLiveNodeList<NodeListType>::length):
     60        (WebCore::CachedLiveNodeList<NodeListType>::item):
     61        (WebCore::CachedLiveNodeList<NodeListType>::memoryCost):
     62       
     63            Templated code moves to header.
     64
     65        (WebCore::LiveNodeList::LiveNodeList): Deleted.
     66        (WebCore::LiveNodeList::~LiveNodeList): Deleted.
     67        (WebCore::LiveNodeList::invalidateCache): Deleted.
     68        (WebCore::LiveNodeList::collectionCanTraverseBackward): Deleted.
     69        (WebCore::LiveNodeList::willValidateIndexCache): Deleted.
     70        * dom/NameNodeList.cpp:
     71        (WebCore::NameNodeList::NameNodeList):
     72        * dom/NameNodeList.h:
     73        * dom/Node.cpp:
     74        (WebCore::Document::invalidateNodeListAndCollectionCaches):
     75        (WebCore::NodeListsNodeData::invalidateCaches):
     76        * dom/TagNodeList.cpp:
     77        (WebCore::TagNodeList::TagNodeList):
     78        (WebCore::HTMLTagNodeList::HTMLTagNodeList):
     79        (WebCore::HTMLTagNodeList::~HTMLTagNodeList):
     80        (WebCore::TagNodeList::nodeMatches): Deleted.
     81        (WebCore::HTMLTagNodeList::nodeMatches): Deleted.
     82        * dom/TagNodeList.h:
     83        (WebCore::TagNodeList::nodeMatches):
     84        (WebCore::HTMLTagNodeList::nodeMatches):
     85        (WebCore::TagNodeList::create): Deleted.
     86        (WebCore::HTMLTagNodeList::nodeMatchesInlined): Deleted.
     87        * html/LabelsNodeList.cpp:
     88        (WebCore::LabelsNodeList::LabelsNodeList):
     89        * html/LabelsNodeList.h:
     90        * html/RadioNodeList.cpp:
     91        (WebCore::RadioNodeList::RadioNodeList):
     92        * html/RadioNodeList.h:
     93
    1942014-03-27  Adenilson Cavalcanti  <cavalcantii@gmail.com>
    295
  • trunk/Source/WebCore/dom/ClassNodeList.cpp

    r165676 r166369  
    3737
    3838ClassNodeList::ClassNodeList(ContainerNode& rootNode, const String& classNames)
    39     : LiveNodeList(rootNode, Type::ClassNodeListType, InvalidateOnClassAttrChange)
     39    : CachedLiveNodeList(rootNode, Type::ClassNodeListType, InvalidateOnClassAttrChange)
    4040    , m_classNames(classNames, document().inQuirksMode())
    4141    , m_originalClassNames(classNames)
     
    4646{
    4747    ownerNode().nodeLists()->removeCacheWithName(this, m_originalClassNames);
    48 }
    49 
    50 bool ClassNodeList::nodeMatches(Element* testNode) const
    51 {
    52     return nodeMatchesInlined(testNode);
    5348}
    5449
  • trunk/Source/WebCore/dom/ClassNodeList.h

    r165676 r166369  
    3838namespace WebCore {
    3939
    40 class ClassNodeList : public LiveNodeList {
     40class ClassNodeList final : public CachedLiveNodeList<ClassNodeList> {
    4141public:
    4242    static PassRefPtr<ClassNodeList> create(ContainerNode& rootNode, const String& classNames)
     
    4747    virtual ~ClassNodeList();
    4848
    49     bool nodeMatchesInlined(Element*) const;
     49    virtual bool nodeMatches(Element*) const override;
    5050
    5151private:
    5252    ClassNodeList(ContainerNode& rootNode, const String& classNames);
    53 
    54     virtual bool nodeMatches(Element*) const override;
    5553
    5654    SpaceSplitString m_classNames;
     
    5856};
    5957
    60 inline bool ClassNodeList::nodeMatchesInlined(Element* testNode) const
     58inline bool ClassNodeList::nodeMatches(Element* element) const
    6159{
    62     if (!testNode->hasClass())
     60    if (!element->hasClass())
    6361        return false;
    6462    if (!m_classNames.size())
     
    6664    // FIXME: DOM4 allows getElementsByClassName to return non StyledElement.
    6765    // https://bugs.webkit.org/show_bug.cgi?id=94718
    68     if (!testNode->isStyledElement())
     66    if (!element->isStyledElement())
    6967        return false;
    70     return testNode->classNames().containsAll(m_classNames);
     68    return element->classNames().containsAll(m_classNames);
    7169}
    7270
  • trunk/Source/WebCore/dom/LiveNodeList.cpp

    r165254 r166369  
    3232namespace WebCore {
    3333
    34 ContainerNode& LiveNodeList::rootNode() const
     34LiveNodeList::LiveNodeList(ContainerNode& ownerNode, Type type, NodeListInvalidationType invalidationType, NodeListRootType rootType)
     35    : m_ownerNode(ownerNode)
     36    , m_rootType(rootType)
     37    , m_invalidationType(invalidationType)
     38    , m_type(static_cast<unsigned>(type))
    3539{
    36     if (isRootedAtDocument() && ownerNode().inDocument())
    37         return ownerNode().document();
    38 
    39     return ownerNode();
     40    ASSERT(m_rootType == static_cast<unsigned>(rootType));
     41    ASSERT(m_invalidationType == static_cast<unsigned>(invalidationType));
     42    ASSERT(m_type == static_cast<unsigned>(type));
    4043}
    4144
    42 template <class NodeListType>
    43 inline bool isMatchingElement(const NodeListType*, Element*);
    44 
    45 template <> inline bool isMatchingElement(const LiveNodeList* nodeList, Element* element)
     45LiveNodeList::~LiveNodeList()
    4646{
    47     return nodeList->nodeMatches(element);
    4847}
    4948
    50 template <> inline bool isMatchingElement(const HTMLTagNodeList* nodeList, Element* element)
    51 {
    52     return nodeList->nodeMatchesInlined(element);
    53 }
    54 
    55 template <> inline bool isMatchingElement(const ClassNodeList* nodeList, Element* element)
    56 {
    57     return nodeList->nodeMatchesInlined(element);
    58 }
    59 
    60 template <class NodeListType>
    61 inline Element* firstMatchingElement(const NodeListType* nodeList, ContainerNode& root)
    62 {
    63     Element* element = ElementTraversal::firstWithin(&root);
    64     while (element && !isMatchingElement(nodeList, element))
    65         element = ElementTraversal::next(element, &root);
    66     return element;
    67 }
    68 
    69 template <class NodeListType>
    70 inline Element* lastMatchingElement(const NodeListType* nodeList, ContainerNode& root)
    71 {
    72     Element* element = ElementTraversal::lastWithin(&root);
    73     while (element && !isMatchingElement(nodeList, element))
    74         element = ElementTraversal::previous(element, &root);
    75     return element;
    76 }
    77 
    78 template <class NodeListType>
    79 inline Element* nextMatchingElement(const NodeListType* nodeList, Element* current, ContainerNode& root)
    80 {
    81     do {
    82         current = ElementTraversal::next(current, &root);
    83     } while (current && !isMatchingElement(nodeList, current));
    84     return current;
    85 }
    86 
    87 template <class NodeListType>
    88 inline Element* previousMatchingElement(const NodeListType* nodeList, Element* current, ContainerNode& root)
    89 {
    90     do {
    91         current = ElementTraversal::previous(current, &root);
    92     } while (current && !isMatchingElement(nodeList, current));
    93     return current;
    94 }
    95 
    96 template <class NodeListType>
    97 inline Element* traverseMatchingElementsForward(const NodeListType* nodeList, Element& current, unsigned count, unsigned& traversedCount, ContainerNode& root)
    98 {
    99     Element* element = &current;
    100     for (traversedCount = 0; traversedCount < count; ++traversedCount) {
    101         element = nextMatchingElement(nodeList, element, root);
    102         if (!element)
    103             return nullptr;
    104     }
    105     return element;
    106 }
    107 
    108 template <class NodeListType>
    109 inline Element* traverseMatchingElementsBackward(const NodeListType* nodeList, Element& current, unsigned count, ContainerNode& root)
    110 {
    111     Element* element = &current;
    112     for (; count; --count) {
    113         element = previousMatchingElement(nodeList, element, root);
    114         if (!element)
    115             return nullptr;
    116     }
    117     return element;
    118 }
    119 
    120 Element* LiveNodeList::collectionFirst() const
    121 {
    122     auto& root = rootNode();
    123     if (type() == Type::HTMLTagNodeListType)
    124         return firstMatchingElement(static_cast<const HTMLTagNodeList*>(this), root);
    125     if (type() == Type::ClassNodeListType)
    126         return firstMatchingElement(static_cast<const ClassNodeList*>(this), root);
    127     return firstMatchingElement(static_cast<const LiveNodeList*>(this), root);
    128 }
    129 
    130 Element* LiveNodeList::collectionLast() const
    131 {
    132     auto& root = rootNode();
    133     if (type() == Type::HTMLTagNodeListType)
    134         return lastMatchingElement(static_cast<const HTMLTagNodeList*>(this), root);
    135     if (type() == Type::ClassNodeListType)
    136         return lastMatchingElement(static_cast<const ClassNodeList*>(this), root);
    137     return lastMatchingElement(static_cast<const LiveNodeList*>(this), root);
    138 }
    139 
    140 Element* LiveNodeList::collectionTraverseForward(Element& current, unsigned count, unsigned& traversedCount) const
    141 {
    142     auto& root = rootNode();
    143     if (type() == Type::HTMLTagNodeListType)
    144         return traverseMatchingElementsForward(static_cast<const HTMLTagNodeList*>(this), current, count, traversedCount, root);
    145     if (type() == Type::ClassNodeListType)
    146         return traverseMatchingElementsForward(static_cast<const ClassNodeList*>(this), current, count, traversedCount, root);
    147     return traverseMatchingElementsForward(static_cast<const LiveNodeList*>(this), current, count, traversedCount, root);
    148 }
    149 
    150 Element* LiveNodeList::collectionTraverseBackward(Element& current, unsigned count) const
    151 {
    152     auto& root = rootNode();
    153     if (type() == Type::HTMLTagNodeListType)
    154         return traverseMatchingElementsBackward(static_cast<const HTMLTagNodeList*>(this), current, count, root);
    155     if (type() == Type::ClassNodeListType)
    156         return traverseMatchingElementsBackward(static_cast<const ClassNodeList*>(this), current, count, root);
    157     return traverseMatchingElementsBackward(static_cast<const LiveNodeList*>(this), current, count, root);
    158 }
    159 
    160 unsigned LiveNodeList::length() const
    161 {
    162     return m_indexCache.nodeCount(*this);
    163 }
    164 
    165 Node* LiveNodeList::item(unsigned offset) const
    166 {
    167     return m_indexCache.nodeAt(*this, offset);
    168 }
    169 
    170 size_t LiveNodeList::memoryCost() const
    171 {
    172     return m_indexCache.memoryCost();
    173 }
    174 
    175 void LiveNodeList::invalidateCache(Document& document) const
    176 {
    177     if (!m_indexCache.hasValidCache())
    178         return;
    179     document.unregisterNodeList(const_cast<LiveNodeList&>(*this));
    180     m_indexCache.invalidate();
    181 }
    18249
    18350Node* LiveNodeList::namedItem(const AtomicString& elementId) const
     
    19158            return element;
    19259        if (!element)
    193             return 0;
     60            return nullptr;
    19461        // In the case of multiple nodes with the same name, just fall through.
    19562    }
     
    20673    }
    20774
    208     return 0;
     75    return nullptr;
    20976}
    21077
  • trunk/Source/WebCore/dom/LiveNodeList.h

    r165103 r166369  
    2828#include "CollectionType.h"
    2929#include "Document.h"
     30#include "ElementTraversal.h"
    3031#include "HTMLNames.h"
    3132#include "NodeList.h"
     
    5556    };
    5657
    57     LiveNodeList(ContainerNode& ownerNode, Type type, NodeListInvalidationType invalidationType, NodeListRootType rootType = NodeListIsRootedAtNode)
    58         : m_ownerNode(ownerNode)
    59         , m_rootType(rootType)
    60         , m_invalidationType(invalidationType)
    61         , m_type(static_cast<unsigned>(type))
    62     {
    63         ASSERT(m_rootType == static_cast<unsigned>(rootType));
    64         ASSERT(m_invalidationType == static_cast<unsigned>(invalidationType));
    65         ASSERT(m_type == static_cast<unsigned>(type));
    66     }
     58    LiveNodeList(ContainerNode& ownerNode, Type, NodeListInvalidationType, NodeListRootType);
    6759    virtual Node* namedItem(const AtomicString&) const override final;
    6860    virtual bool nodeMatches(Element*) const = 0;
    6961
    70     virtual ~LiveNodeList()
    71     {
    72         if (m_indexCache.hasValidCache())
    73             document().unregisterNodeList(*this);
    74     }
    75 
    76     // DOM API
    77     virtual unsigned length() const override final;
    78     virtual Node* item(unsigned offset) const override final;
    79     virtual size_t memoryCost() const override;
     62    virtual ~LiveNodeList();
    8063
    8164    ALWAYS_INLINE bool isRootedAtDocument() const { return m_rootType == NodeListIsRootedAtDocument; }
     
    8366    ALWAYS_INLINE Type type() const { return static_cast<Type>(m_type); }
    8467    ContainerNode& ownerNode() const { return const_cast<ContainerNode&>(m_ownerNode.get()); }
    85     ALWAYS_INLINE void invalidateCache(const QualifiedName* attrName) const
     68    ALWAYS_INLINE void invalidateCacheForAttribute(const QualifiedName* attrName) const
    8669    {
    8770        if (!attrName || shouldInvalidateTypeOnAttributeChange(invalidationType(), *attrName))
    8871            invalidateCache(document());
    8972    }
    90     void invalidateCache(Document&) const;
     73    virtual void invalidateCache(Document&) const = 0;
     74
     75protected:
     76    Document& document() const { return m_ownerNode->document(); }
     77    ContainerNode& rootNode() const;
     78
     79    ALWAYS_INLINE NodeListRootType rootType() const { return static_cast<NodeListRootType>(m_rootType); }
     80
     81private:
     82    virtual bool isLiveNodeList() const override { return true; }
     83
     84    Element* iterateForPreviousElement(Element* current) const;
     85
     86    Ref<ContainerNode> m_ownerNode;
     87
     88    const unsigned m_rootType : 1;
     89    const unsigned m_invalidationType : 4;
     90    const unsigned m_type : 3;
     91};
     92
     93template <class NodeListType>
     94class CachedLiveNodeList : public LiveNodeList {
     95public:
     96    virtual ~CachedLiveNodeList();
     97
     98    virtual unsigned length() const override final;
     99    virtual Node* item(unsigned offset) const override final;
    91100
    92101    // For CollectionIndexCache
     
    96105    Element* collectionTraverseBackward(Element&, unsigned count) const;
    97106    bool collectionCanTraverseBackward() const { return true; }
    98     void willValidateIndexCache() const { document().registerNodeList(const_cast<LiveNodeList&>(*this)); }
     107    void willValidateIndexCache() const;
     108
     109    virtual void invalidateCache(Document&) const;
     110    virtual size_t memoryCost() const override;
    99111
    100112protected:
    101     Document& document() const { return m_ownerNode->document(); }
    102     ContainerNode& rootNode() const;
    103 
    104     ALWAYS_INLINE NodeListRootType rootType() const { return static_cast<NodeListRootType>(m_rootType); }
     113    CachedLiveNodeList(ContainerNode& rootNode, Type, NodeListInvalidationType, NodeListRootType = NodeListIsRootedAtNode);
    105114
    106115private:
    107     virtual bool isLiveNodeList() const override { return true; }
    108 
    109     Element* iterateForPreviousElement(Element* current) const;
    110 
    111     Ref<ContainerNode> m_ownerNode;
    112 
    113     mutable CollectionIndexCache<LiveNodeList, Element> m_indexCache;
    114 
    115     const unsigned m_rootType : 1;
    116     const unsigned m_invalidationType : 4;
    117     const unsigned m_type : 3;
     116    mutable CollectionIndexCache<NodeListType, Element> m_indexCache;
    118117};
    119118
     
    142141}
    143142
     143inline ContainerNode& LiveNodeList::rootNode() const
     144{
     145    if (isRootedAtDocument() && ownerNode().inDocument())
     146        return ownerNode().document();
     147
     148    return ownerNode();
     149}
     150
     151template <class NodeListType>
     152CachedLiveNodeList<NodeListType>::CachedLiveNodeList(ContainerNode& ownerNode, Type type, NodeListInvalidationType invalidationType, NodeListRootType rootType)
     153    : LiveNodeList(ownerNode, type, invalidationType, rootType)
     154{
     155}
     156
     157template <class NodeListType>
     158CachedLiveNodeList<NodeListType>::~CachedLiveNodeList()
     159{
     160    if (m_indexCache.hasValidCache())
     161        document().unregisterNodeList(*this);
     162}
     163
     164template <class NodeListType>
     165Element* CachedLiveNodeList<NodeListType>::collectionFirst() const
     166{
     167    auto& root = rootNode();
     168    Element* element = ElementTraversal::firstWithin(&root);
     169    while (element && !static_cast<const NodeListType*>(this)->nodeMatches(element))
     170        element = ElementTraversal::next(element, &root);
     171    return element;
     172}
     173
     174template <class NodeListType>
     175Element* CachedLiveNodeList<NodeListType>::collectionLast() const
     176{
     177    auto& root = rootNode();
     178    Element* element = ElementTraversal::lastWithin(&root);
     179    while (element && !static_cast<const NodeListType*>(this)->nodeMatches(element))
     180        element = ElementTraversal::previous(element, &root);
     181    return element;
     182}
     183
     184template <class NodeListType>
     185inline Element* nextMatchingElement(const NodeListType* nodeList, Element* current, ContainerNode& root)
     186{
     187    do {
     188        current = ElementTraversal::next(current, &root);
     189    } while (current && !static_cast<const NodeListType*>(nodeList)->nodeMatches(current));
     190    return current;
     191}
     192
     193template <class NodeListType>
     194Element* CachedLiveNodeList<NodeListType>::collectionTraverseForward(Element& current, unsigned count, unsigned& traversedCount) const
     195{
     196    auto& root = rootNode();
     197    Element* element = &current;
     198    for (traversedCount = 0; traversedCount < count; ++traversedCount) {
     199        element = nextMatchingElement(static_cast<const NodeListType*>(this), element, root);
     200        if (!element)
     201            return nullptr;
     202    }
     203    return element;
     204}
     205
     206template <class NodeListType>
     207inline Element* previousMatchingElement(const NodeListType* nodeList, Element* current, ContainerNode& root)
     208{
     209    do {
     210        current = ElementTraversal::previous(current, &root);
     211    } while (current && !nodeList->nodeMatches(current));
     212    return current;
     213}
     214
     215template <class NodeListType>
     216Element* CachedLiveNodeList<NodeListType>::collectionTraverseBackward(Element& current, unsigned count) const
     217{
     218    auto& root = rootNode();
     219    Element* element = &current;
     220    for (; count; --count) {
     221        element = previousMatchingElement(static_cast<const NodeListType*>(this), element, root);
     222        if (!element)
     223            return nullptr;
     224    }
     225    return element;
     226}
     227template <class NodeListType>
     228void CachedLiveNodeList<NodeListType>::willValidateIndexCache() const
     229{
     230    document().registerNodeList(const_cast<NodeListType&>(static_cast<const NodeListType&>(*this)));
     231}
     232
     233template <class NodeListType>
     234void CachedLiveNodeList<NodeListType>::invalidateCache(Document& document) const
     235{
     236    if (!m_indexCache.hasValidCache())
     237        return;
     238    document.unregisterNodeList(const_cast<NodeListType&>(static_cast<const NodeListType&>(*this)));
     239    m_indexCache.invalidate();
     240}
     241
     242template <class NodeListType>
     243unsigned CachedLiveNodeList<NodeListType>::length() const
     244{
     245    return m_indexCache.nodeCount(static_cast<const NodeListType&>(*this));
     246}
     247
     248template <class NodeListType>
     249Node* CachedLiveNodeList<NodeListType>::item(unsigned offset) const
     250{
     251    return m_indexCache.nodeAt(static_cast<const NodeListType&>(*this), offset);
     252}
     253
     254template <class NodeListType>
     255size_t CachedLiveNodeList<NodeListType>::memoryCost() const
     256{
     257    return m_indexCache.memoryCost();
     258}
     259
    144260} // namespace WebCore
    145261
  • trunk/Source/WebCore/dom/NameNodeList.cpp

    r164654 r166369  
    3131
    3232NameNodeList::NameNodeList(ContainerNode& rootNode, const AtomicString& name)
    33     : LiveNodeList(rootNode, Type::NameNodeListType, InvalidateOnNameAttrChange)
     33    : CachedLiveNodeList(rootNode, Type::NameNodeListType, InvalidateOnNameAttrChange)
    3434    , m_name(name)
    3535{
  • trunk/Source/WebCore/dom/NameNodeList.h

    r164654 r166369  
    3232
    3333// NodeList which lists all Nodes in a Element with a given "name" attribute
    34 class NameNodeList : public LiveNodeList {
     34class NameNodeList final : public CachedLiveNodeList<NameNodeList> {
    3535public:
    3636    static PassRefPtr<NameNodeList> create(ContainerNode& rootNode, Type type, const AtomicString& name)
     
    4242    virtual ~NameNodeList();
    4343
     44    virtual bool nodeMatches(Element*) const override;
     45
    4446private:
    4547    NameNodeList(ContainerNode& rootNode, const AtomicString& name);
    46 
    47     virtual bool nodeMatches(Element*) const override;
    4848
    4949    AtomicString m_name;
  • trunk/Source/WebCore/dom/Node.cpp

    r165607 r166369  
    727727    HashSet<LiveNodeList*> lists = std::move(m_listsInvalidatedAtDocument);
    728728    for (auto* list : lists)
    729         list->invalidateCache(attrName);
     729        list->invalidateCacheForAttribute(attrName);
    730730    HashSet<HTMLCollection*> collections = std::move(m_collectionsInvalidatedAtDocument);
    731731    for (auto* collection : collections)
     
    16861686{
    16871687    for (auto& atomicName : m_atomicNameCaches)
    1688         atomicName.value->invalidateCache(attrName);
     1688        atomicName.value->invalidateCacheForAttribute(attrName);
    16891689
    16901690    for (auto& name : m_nameCaches)
    1691         name.value->invalidateCache(attrName);
     1691        name.value->invalidateCacheForAttribute(attrName);
    16921692
    16931693    for (auto& collection : m_cachedCollections)
     
    16981698
    16991699    for (auto& tagNodeList : m_tagNodeListCacheNS)
    1700         tagNodeList.value->invalidateCache(nullptr);
     1700        tagNodeList.value->invalidateCacheForAttribute(nullptr);
    17011701}
    17021702
  • trunk/Source/WebCore/dom/TagNodeList.cpp

    r164654 r166369  
    2929namespace WebCore {
    3030
    31 TagNodeList::TagNodeList(ContainerNode& rootNode, Type type, const AtomicString& namespaceURI, const AtomicString& localName)
    32     : LiveNodeList(rootNode, type, DoNotInvalidateOnAttributeChanges)
     31TagNodeList::TagNodeList(ContainerNode& rootNode, const AtomicString& namespaceURI, const AtomicString& localName)
     32    : CachedLiveNodeList(rootNode, Type::TagNodeListType, DoNotInvalidateOnAttributeChanges)
    3333    , m_namespaceURI(namespaceURI)
    3434    , m_localName(localName)
     
    4545}
    4646
    47 bool TagNodeList::nodeMatches(Element* testNode) const
    48 {
    49     // Implements http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-getelementsbytagnamens
    50     if (m_localName != starAtom && m_localName != testNode->localName())
    51         return false;
    52 
    53     return m_namespaceURI == starAtom || m_namespaceURI == testNode->namespaceURI();
    54 }
    55 
    5647HTMLTagNodeList::HTMLTagNodeList(ContainerNode& rootNode, const AtomicString& localName)
    57     : TagNodeList(rootNode, Type::HTMLTagNodeListType, starAtom, localName)
     48    : CachedLiveNodeList(rootNode, Type::HTMLTagNodeListType, DoNotInvalidateOnAttributeChanges)
     49    , m_localName(localName)
    5850    , m_loweredLocalName(localName.lower())
    5951{
    6052}
    6153
    62 bool HTMLTagNodeList::nodeMatches(Element* testNode) const
     54HTMLTagNodeList::~HTMLTagNodeList()
    6355{
    64     return nodeMatchesInlined(testNode);
     56    ownerNode().nodeLists()->removeCacheWithAtomicName(this, m_localName);
    6557}
    6658
  • trunk/Source/WebCore/dom/TagNodeList.h

    r164654 r166369  
    3232
    3333// NodeList that limits to a particular tag.
    34 class TagNodeList : public LiveNodeList {
     34class TagNodeList final : public CachedLiveNodeList<TagNodeList> {
    3535public:
    3636    static PassRefPtr<TagNodeList> create(ContainerNode& rootNode, const AtomicString& namespaceURI, const AtomicString& localName)
    3737    {
    3838        ASSERT(namespaceURI != starAtom);
    39         return adoptRef(new TagNodeList(rootNode, Type::TagNodeListType, namespaceURI, localName));
     39        return adoptRef(new TagNodeList(rootNode, namespaceURI, localName));
    4040    }
    4141
     
    4343    {
    4444        ASSERT_UNUSED(type, type == Type::TagNodeListType);
    45         return adoptRef(new TagNodeList(rootNode, Type::TagNodeListType, starAtom, localName));
     45        return adoptRef(new TagNodeList(rootNode, starAtom, localName));
    4646    }
    4747
    4848    virtual ~TagNodeList();
    4949
     50    virtual bool nodeMatches(Element*) const override;
     51
    5052protected:
    51     TagNodeList(ContainerNode& rootNode, Type, const AtomicString& namespaceURI, const AtomicString& localName);
    52 
    53     virtual bool nodeMatches(Element*) const override;
     53    TagNodeList(ContainerNode& rootNode, const AtomicString& namespaceURI, const AtomicString& localName);
    5454
    5555    AtomicString m_namespaceURI;
     
    5757};
    5858
    59 class HTMLTagNodeList : public TagNodeList {
     59inline bool TagNodeList::nodeMatches(Element* element) const
     60{
     61    // Implements http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-getelementsbytagnamens
     62    if (m_localName != starAtom && m_localName != element->localName())
     63        return false;
     64
     65    return m_namespaceURI == starAtom || m_namespaceURI == element->namespaceURI();
     66}
     67
     68class HTMLTagNodeList final : public CachedLiveNodeList<HTMLTagNodeList> {
    6069public:
    6170    static PassRefPtr<HTMLTagNodeList> create(ContainerNode& rootNode, Type type, const AtomicString& localName)
     
    6574    }
    6675
    67     bool nodeMatchesInlined(Element*) const;
     76    virtual ~HTMLTagNodeList();
     77
     78    virtual bool nodeMatches(Element*) const override;
    6879
    6980private:
    7081    HTMLTagNodeList(ContainerNode& rootNode, const AtomicString& localName);
    7182
    72     virtual bool nodeMatches(Element*) const override;
    73 
     83    AtomicString m_localName;
    7484    AtomicString m_loweredLocalName;
    7585};
    7686
    77 inline bool HTMLTagNodeList::nodeMatchesInlined(Element* testNode) const
     87inline bool HTMLTagNodeList::nodeMatches(Element* element) const
    7888{
    7989    // Implements http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-getelementsbytagname
    80     if (m_localName != starAtom) {
    81         const AtomicString& localName = testNode->isHTMLElement() ? m_loweredLocalName : m_localName;
    82         if (localName != testNode->localName())
    83             return false;
    84     }
    85     ASSERT(m_namespaceURI == starAtom);
    86     return true;
     90    if (m_localName == starAtom)
     91        return true;
     92    const AtomicString& localName = element->isHTMLElement() ? m_loweredLocalName : m_localName;
     93    return localName == element->localName();
    8794}
    8895
  • trunk/Source/WebCore/html/LabelsNodeList.cpp

    r164654 r166369  
    3535
    3636LabelsNodeList::LabelsNodeList(LabelableElement& forNode)
    37     : LiveNodeList(forNode, Type::LabelsNodeListType, InvalidateOnForAttrChange, NodeListIsRootedAtDocument)
     37    : CachedLiveNodeList(forNode, Type::LabelsNodeListType, InvalidateOnForAttrChange, NodeListIsRootedAtDocument)
    3838{
    3939}
  • trunk/Source/WebCore/html/LabelsNodeList.h

    r164654 r166369  
    3131namespace WebCore {
    3232
    33 class LabelsNodeList final : public LiveNodeList {
     33class LabelsNodeList final : public CachedLiveNodeList<LabelsNodeList> {
    3434public:
    3535    static PassRef<LabelsNodeList> create(LabelableElement& forNode, Type type, const AtomicString&)
     
    4040    ~LabelsNodeList();
    4141
    42 protected:
     42    virtual bool nodeMatches(Element*) const override;
     43
     44private:
    4345    explicit LabelsNodeList(LabelableElement& forNode);
    44 
    45     virtual bool nodeMatches(Element*) const override;
    4646};
    4747
  • trunk/Source/WebCore/html/RadioNodeList.cpp

    r164654 r166369  
    3939
    4040RadioNodeList::RadioNodeList(ContainerNode& rootNode, const AtomicString& name)
    41     : LiveNodeList(rootNode, Type::RadioNodeListType, InvalidateForFormControls, isHTMLFormElement(rootNode) ? NodeListIsRootedAtDocument : NodeListIsRootedAtNode)
     41    : CachedLiveNodeList(rootNode, Type::RadioNodeListType, InvalidateForFormControls, isHTMLFormElement(rootNode) ? NodeListIsRootedAtDocument : NodeListIsRootedAtNode)
    4242    , m_name(name)
    4343{
  • trunk/Source/WebCore/html/RadioNodeList.h

    r164654 r166369  
    3333namespace WebCore {
    3434
    35 class RadioNodeList : public LiveNodeList {
     35class RadioNodeList final : public CachedLiveNodeList<RadioNodeList> {
    3636public:
    3737    static PassRefPtr<RadioNodeList> create(ContainerNode& rootNode, Type type, const AtomicString& name)
     
    4646    void setValue(const String&);
    4747
    48 protected:
    4948    virtual bool nodeMatches(Element*) const override;
    5049
Note: See TracChangeset for help on using the changeset viewer.