Changeset 123281 in webkit


Ignore:
Timestamp:
Jul 20, 2012 6:03:17 PM (12 years ago)
Author:
rniwa@webkit.org
Message:

Unify HTMLCollection and DynamicNodeList
https://bugs.webkit.org/show_bug.cgi?id=91335

Reviewed by Anders Carlsson.

This is the grand unification of HTMLCollection and DynamicNodeList.

It merges implementations of item() and length() in ChildNodeList, DynamicNodeList,
and HTMLCollection. The unified implementation is based on the one used for HTMLCollection,
that has been improved over the last few days; see r122660 and r122672 for examples.

There are five key changes:

  1. Made itemBeforeOrAfter aware of DynamicNodeList.
  2. itemBeforeOrAfter and related functions take and return Node* to support ChildNodeList.
  3. Renamed InvalidCollectionType to NodeListCollectionType since DynamicNodeLists need to be

identified itemBeforeOrAfter.

  1. Renamed itemAfter to virtualItemAfter in subclasses of HTMLCollection, and devirtualized

itemAfter used in common cases to avoid performance regressions. To make this intent clear,
SupportItemBefore and DoNotSupportItemBefore have been renamed to DoesNotOverrideItemAfter
and OverridesItemAfter. This change also help us detect a subclass of HTMLCollection that
passes in a wrong value to ItemBeforeSupportType by making forward iterations fail (hit an
assertion or doesn't iterate at all) as well as backward iterations.

  1. Restricted the use of elementsArrayOffset to subclasses that provide virtualItemAfter.

This patch completes my effort to share code between HTMLCollection and DynamicNodeList.

  • dom/ChildNodeList.cpp:

(WebCore::ChildNodeList::ChildNodeList):
(WebCore): Removed length() and item().
(WebCore::ChildNodeList::nodeMatches):

  • dom/ChildNodeList.h:

(ChildNodeList):

  • dom/ClassNodeList.cpp:

(WebCore::ClassNodeList::ClassNodeList):

  • dom/Document.cpp:

(WebCore::Document::registerNodeListCache):
(WebCore::Document::unregisterNodeListCache):

  • dom/DynamicNodeList.cpp:

(WebCore::DynamicNodeListCacheBase::invalidateCache):
(WebCore::DynamicNodeList::length):
(WebCore::DynamicNodeList::item):

  • dom/DynamicNodeList.h:

(WebCore::DynamicNodeListCacheBase::DynamicNodeListCacheBase): Takes new boolean argument
shouldOnlyIncludeDirectChildren indicating whether the non-child descendents should be
included or not. This is necessary to identify ChildNodeList in itemBeforeOrAfter.
(WebCore::DynamicNodeListCacheBase::ownerNode): Moved from DynamicNodeListCacheBase and
HTMLCollectionCacheBase.
(WebCore::DynamicNodeListCacheBase::document): Moved from DynamicNodeListCacheBase.
(WebCore::DynamicNodeListCacheBase::rootNode): Ditto.
(WebCore::DynamicNodeListCacheBase::overridesItemAfter): Renamed from supportsItemBefore
and the return value has been negated.
(WebCore::DynamicNodeListCacheBase::shouldOnlyIncludeDirectChildren): Added.
(WebCore::DynamicNodeListCacheBase):
(WebCore::DynamicNodeList::DynamicNodeList): Takes NodeListType to determine the value of
shouldOnlyIncludeDirectChildren.
(DynamicNodeList):
(WebCore::DynamicSubtreeNodeList::~DynamicSubtreeNodeList):
(WebCore::DynamicSubtreeNodeList::DynamicSubtreeNodeList):

  • dom/MicroDataItemList.cpp:

(WebCore::MicroDataItemList::MicroDataItemList):

  • dom/NameNodeList.cpp:

(WebCore::NameNodeList::NameNodeList):

  • dom/TagNodeList.cpp:

(WebCore::TagNodeList::TagNodeList):

  • html/CollectionType.h:
  • html/HTMLAllCollection.cpp:

(WebCore::HTMLAllCollection::HTMLAllCollection):

  • html/HTMLCollection.cpp:

(WebCore::shouldOnlyIncludeDirectChildren):
(WebCore::rootTypeFromCollectionType):
(WebCore::invalidationTypeExcludingIdAndNameAttributes):
(WebCore::HTMLCollection::HTMLCollection):
(WebCore::HTMLCollection::create):
(WebCore::HTMLCollection::~HTMLCollection):
(WebCore::isAcceptableElement):
(WebCore::firstNode): Extracted from itemBeforeOrAfter.
(WebCore::DynamicNodeListCacheBase::iterateForNextNode): Ditto.
(WebCore::DynamicNodeListCacheBase::itemBeforeOrAfter): Takes and returns Node*.
Special case ChildNodeList since there is no need to skip any node. When "this" is a
node list, call nodeMatches instead of isAcceptableElement.
(WebCore::DynamicNodeListCacheBase::itemBefore): No longer takes offsetInArray since
the use of elementsArrayOffset has been restricted to HTMLCollections that provides
virtualItemAfter.
(WebCore::DynamicNodeListCacheBase::itemAfter): Calls virtualItemAfter if necessary.
Otherwise assert offsetInArray is zero since we should never be using this variable
when virtualItemAfter is not provided.
(WebCore::DynamicNodeListCacheBase::isLastItemCloserThanLastOrCachedItem):
(WebCore::DynamicNodeListCacheBase::isFirstItemCloserThanCachedItem):
(WebCore::DynamicNodeListCacheBase::setItemCache): Updates m_cachedElementsArrayOffset
in HTMLCollection if and only if virtualItemAfter is provided. This is safe because
node lists never provide virtualItemAfter.
(WebCore::DynamicNodeListCacheBase::cachedElementsArrayOffset): Similarly, returns
m_cachedElementsArrayOffset if virtualItemAfter is provided.
(WebCore::DynamicNodeListCacheBase::lengthCommon):
(WebCore::DynamicNodeListCacheBase::itemCommon): Note that supportsItemBefore() is
equivalent to !overridesItemAfter() here.
(WebCore::DynamicNodeListCacheBase::itemBeforeOrAfterCachedItem): Uses Node* through
out the function. Since itemBefore never uses offsetInArray, always sets 0 for that.
Note that we never call itemBefore and virtualItemAfter on the same object.
(WebCore::HTMLCollection::virtualItemAfter): Added only to make the class "concrete".
(WebCore::HTMLCollection::namedItem):
(WebCore::HTMLCollection::updateNameCache):
(WebCore::HTMLCollection::tags):

  • html/HTMLCollection.h:

(WebCore::HTMLCollectionCacheBase::HTMLCollectionCacheBase):
(HTMLCollectionCacheBase):
(WebCore::HTMLCollection::length):
(WebCore::HTMLCollection::item):
(WebCore::HTMLCollection::base):
(HTMLCollection):

  • html/HTMLFormCollection.cpp:

(WebCore::HTMLFormCollection::HTMLFormCollection):
(WebCore::HTMLFormCollection::virtualItemAfter):

  • html/HTMLFormCollection.h:

(HTMLFormCollection):

  • html/HTMLNameCollection.cpp:

(WebCore::HTMLNameCollection::HTMLNameCollection):
(WebCore::HTMLNameCollection::virtualItemAfter):

  • html/HTMLNameCollection.h:

(HTMLNameCollection):

  • html/HTMLOptionsCollection.cpp:

(WebCore::HTMLOptionsCollection::HTMLOptionsCollection):

  • html/HTMLPropertiesCollection.cpp:

(WebCore::HTMLPropertiesCollection::HTMLPropertiesCollection):
(WebCore::HTMLPropertiesCollection::virtualItemAfter):
(WebCore::HTMLPropertiesCollection::updateNameCache):

  • html/HTMLPropertiesCollection.h:

(HTMLPropertiesCollection):

  • html/HTMLTableRowsCollection.cpp:

(WebCore::HTMLTableRowsCollection::HTMLTableRowsCollection):
(WebCore::HTMLTableRowsCollection::virtualItemAfter):

  • html/HTMLTableRowsCollection.h:

(HTMLTableRowsCollection):

  • html/LabelsNodeList.cpp:

(WebCore::LabelsNodeList::LabelsNodeList):

  • html/RadioNodeList.cpp:

(WebCore::RadioNodeList::RadioNodeList):

Location:
trunk/Source/WebCore
Files:
25 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r123276 r123281  
     12012-07-18  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Unify HTMLCollection and DynamicNodeList
     4        https://bugs.webkit.org/show_bug.cgi?id=91335
     5
     6        Reviewed by Anders Carlsson.
     7
     8        This is the grand unification of HTMLCollection and DynamicNodeList.
     9
     10        It merges implementations of item() and length() in ChildNodeList, DynamicNodeList,
     11        and HTMLCollection. The unified implementation is based on the one used for HTMLCollection,
     12        that has been improved over the last few days; see r122660 and r122672 for examples.
     13
     14        There are five key changes:
     15        1. Made itemBeforeOrAfter aware of DynamicNodeList.
     16        2. itemBeforeOrAfter and related functions take and return Node* to support ChildNodeList.
     17        3. Renamed InvalidCollectionType to NodeListCollectionType since DynamicNodeLists need to be
     18        identified itemBeforeOrAfter.
     19        4. Renamed itemAfter to virtualItemAfter in subclasses of HTMLCollection, and devirtualized
     20        itemAfter used in common cases to avoid performance regressions. To make this intent clear,
     21        SupportItemBefore and DoNotSupportItemBefore have been renamed to DoesNotOverrideItemAfter
     22        and OverridesItemAfter. This change also help us detect a subclass of HTMLCollection that
     23        passes in a wrong value to ItemBeforeSupportType by making forward iterations fail (hit an
     24        assertion or doesn't iterate at all) as well as backward iterations.
     25        5. Restricted the use of elementsArrayOffset to subclasses that provide virtualItemAfter.
     26
     27        This patch completes my effort to share code between HTMLCollection and DynamicNodeList.
     28
     29        * dom/ChildNodeList.cpp:
     30        (WebCore::ChildNodeList::ChildNodeList):
     31        (WebCore): Removed length() and item().
     32        (WebCore::ChildNodeList::nodeMatches):
     33        * dom/ChildNodeList.h:
     34        (ChildNodeList):
     35        * dom/ClassNodeList.cpp:
     36        (WebCore::ClassNodeList::ClassNodeList):
     37        * dom/Document.cpp:
     38        (WebCore::Document::registerNodeListCache):
     39        (WebCore::Document::unregisterNodeListCache):
     40        * dom/DynamicNodeList.cpp:
     41        (WebCore::DynamicNodeListCacheBase::invalidateCache):
     42        (WebCore::DynamicNodeList::length):
     43        (WebCore::DynamicNodeList::item):
     44        * dom/DynamicNodeList.h:
     45        (WebCore::DynamicNodeListCacheBase::DynamicNodeListCacheBase): Takes new boolean argument
     46        shouldOnlyIncludeDirectChildren indicating whether the non-child descendents should be
     47        included or not. This is necessary to identify ChildNodeList in itemBeforeOrAfter.
     48        (WebCore::DynamicNodeListCacheBase::ownerNode): Moved from DynamicNodeListCacheBase and
     49        HTMLCollectionCacheBase.
     50        (WebCore::DynamicNodeListCacheBase::document): Moved from DynamicNodeListCacheBase.
     51        (WebCore::DynamicNodeListCacheBase::rootNode): Ditto.
     52        (WebCore::DynamicNodeListCacheBase::overridesItemAfter): Renamed from supportsItemBefore
     53        and the return value has been negated.
     54        (WebCore::DynamicNodeListCacheBase::shouldOnlyIncludeDirectChildren): Added.
     55        (WebCore::DynamicNodeListCacheBase):
     56        (WebCore::DynamicNodeList::DynamicNodeList): Takes NodeListType to determine the value of
     57        shouldOnlyIncludeDirectChildren.
     58        (DynamicNodeList):
     59        (WebCore::DynamicSubtreeNodeList::~DynamicSubtreeNodeList):
     60        (WebCore::DynamicSubtreeNodeList::DynamicSubtreeNodeList):
     61        * dom/MicroDataItemList.cpp:
     62        (WebCore::MicroDataItemList::MicroDataItemList):
     63        * dom/NameNodeList.cpp:
     64        (WebCore::NameNodeList::NameNodeList):
     65        * dom/TagNodeList.cpp:
     66        (WebCore::TagNodeList::TagNodeList):
     67        * html/CollectionType.h:
     68        * html/HTMLAllCollection.cpp:
     69        (WebCore::HTMLAllCollection::HTMLAllCollection):
     70        * html/HTMLCollection.cpp:
     71        (WebCore::shouldOnlyIncludeDirectChildren):
     72        (WebCore::rootTypeFromCollectionType):
     73        (WebCore::invalidationTypeExcludingIdAndNameAttributes):
     74        (WebCore::HTMLCollection::HTMLCollection):
     75        (WebCore::HTMLCollection::create):
     76        (WebCore::HTMLCollection::~HTMLCollection):
     77        (WebCore::isAcceptableElement):
     78        (WebCore::firstNode): Extracted from itemBeforeOrAfter.
     79        (WebCore::DynamicNodeListCacheBase::iterateForNextNode): Ditto.
     80        (WebCore::DynamicNodeListCacheBase::itemBeforeOrAfter): Takes and returns Node*.
     81        Special case ChildNodeList since there is no need to skip any node. When "this" is a
     82        node list, call nodeMatches instead of isAcceptableElement.
     83        (WebCore::DynamicNodeListCacheBase::itemBefore): No longer takes offsetInArray since
     84        the use of elementsArrayOffset has been restricted to HTMLCollections that provides
     85        virtualItemAfter.
     86        (WebCore::DynamicNodeListCacheBase::itemAfter): Calls virtualItemAfter if necessary.
     87        Otherwise assert offsetInArray is zero since we should never be using this variable
     88        when virtualItemAfter is not provided.
     89        (WebCore::DynamicNodeListCacheBase::isLastItemCloserThanLastOrCachedItem):
     90        (WebCore::DynamicNodeListCacheBase::isFirstItemCloserThanCachedItem):
     91        (WebCore::DynamicNodeListCacheBase::setItemCache): Updates m_cachedElementsArrayOffset
     92        in HTMLCollection if and only if virtualItemAfter is provided. This is safe because
     93        node lists never provide virtualItemAfter.
     94        (WebCore::DynamicNodeListCacheBase::cachedElementsArrayOffset): Similarly, returns
     95        m_cachedElementsArrayOffset if virtualItemAfter is provided.
     96        (WebCore::DynamicNodeListCacheBase::lengthCommon):
     97        (WebCore::DynamicNodeListCacheBase::itemCommon): Note that supportsItemBefore() is
     98        equivalent to !overridesItemAfter() here.
     99        (WebCore::DynamicNodeListCacheBase::itemBeforeOrAfterCachedItem): Uses Node* through
     100        out the function. Since itemBefore never uses offsetInArray, always sets 0 for that.
     101        Note that we never call itemBefore and virtualItemAfter on the same object.
     102        (WebCore::HTMLCollection::virtualItemAfter): Added only to make the class "concrete".
     103        (WebCore::HTMLCollection::namedItem):
     104        (WebCore::HTMLCollection::updateNameCache):
     105        (WebCore::HTMLCollection::tags):
     106        * html/HTMLCollection.h:
     107        (WebCore::HTMLCollectionCacheBase::HTMLCollectionCacheBase):
     108        (HTMLCollectionCacheBase):
     109        (WebCore::HTMLCollection::length):
     110        (WebCore::HTMLCollection::item):
     111        (WebCore::HTMLCollection::base):
     112        (HTMLCollection):
     113        * html/HTMLFormCollection.cpp:
     114        (WebCore::HTMLFormCollection::HTMLFormCollection):
     115        (WebCore::HTMLFormCollection::virtualItemAfter):
     116        * html/HTMLFormCollection.h:
     117        (HTMLFormCollection):
     118        * html/HTMLNameCollection.cpp:
     119        (WebCore::HTMLNameCollection::HTMLNameCollection):
     120        (WebCore::HTMLNameCollection::virtualItemAfter):
     121        * html/HTMLNameCollection.h:
     122        (HTMLNameCollection):
     123        * html/HTMLOptionsCollection.cpp:
     124        (WebCore::HTMLOptionsCollection::HTMLOptionsCollection):
     125        * html/HTMLPropertiesCollection.cpp:
     126        (WebCore::HTMLPropertiesCollection::HTMLPropertiesCollection):
     127        (WebCore::HTMLPropertiesCollection::virtualItemAfter):
     128        (WebCore::HTMLPropertiesCollection::updateNameCache):
     129        * html/HTMLPropertiesCollection.h:
     130        (HTMLPropertiesCollection):
     131        * html/HTMLTableRowsCollection.cpp:
     132        (WebCore::HTMLTableRowsCollection::HTMLTableRowsCollection):
     133        (WebCore::HTMLTableRowsCollection::virtualItemAfter):
     134        * html/HTMLTableRowsCollection.h:
     135        (HTMLTableRowsCollection):
     136        * html/LabelsNodeList.cpp:
     137        (WebCore::LabelsNodeList::LabelsNodeList):
     138        * html/RadioNodeList.cpp:
     139        (WebCore::RadioNodeList::RadioNodeList):
     140
    11412012-07-20  Joshua Bell  <jsbell@chromium.org>
    2142
  • trunk/Source/WebCore/dom/ChildNodeList.cpp

    r122498 r123281  
    2929
    3030ChildNodeList::ChildNodeList(PassRefPtr<Node> node)
    31     : DynamicNodeList(node, NodeListIsRootedAtNode, DoNotInvalidateOnAttributeChanges)
     31    : DynamicNodeList(node, ChildNodeListType, NodeListIsRootedAtNode, DoNotInvalidateOnAttributeChanges)
    3232{
    3333}
     
    3838}
    3939
    40 unsigned ChildNodeList::length() const
    41 {
    42     if (isLengthCacheValid())
    43         return cachedLength();
    44 
    45     unsigned len = 0;
    46     for (Node* n = rootNode()->firstChild(); n; n = n->nextSibling())
    47         len++;
    48 
    49     setLengthCache(len);
    50 
    51     return len;
    52 }
    53 
    54 Node* ChildNodeList::item(unsigned index) const
    55 {
    56     unsigned int pos = 0;
    57     Node* n = rootNode()->firstChild();
    58 
    59     if (isItemCacheValid()) {
    60         if (index == cachedItemOffset())
    61             return cachedItem();
    62 
    63         int diff = index - cachedItemOffset();
    64         unsigned dist = abs(diff);
    65         if (dist < index) {
    66             n = cachedItem();
    67             pos = cachedItemOffset();
    68         }
    69     }
    70 
    71     if (isLengthCacheValid()) {
    72         if (index >= cachedLength())
    73             return 0;
    74 
    75         int diff = index - pos;
    76         unsigned dist = abs(diff);
    77         if (dist > cachedLength() - 1 - index) {
    78             n = rootNode()->lastChild();
    79             pos = cachedLength() - 1;
    80         }
    81     }
    82 
    83     if (pos <= index) {
    84         while (n && pos < index) {
    85             n = n->nextSibling();
    86             ++pos;
    87         }
    88     } else {
    89         while (n && pos > index) {
    90             n = n->previousSibling();
    91             --pos;
    92         }
    93     }
    94 
    95     if (n) {
    96         setItemCache(n, pos);
    97         return n;
    98     }
    99 
    100     return 0;
    101 }
    102 
    10340bool ChildNodeList::nodeMatches(Element* testNode) const
    10441{
    105     // Note: Due to the overrides of the length and item functions above,
    106     // this function will be called only by DynamicNodeList::itemWithName,
     42    // This function will be called only by DynamicNodeList::itemWithName,
    10743    // for an element that was located with getElementById.
    10844    return testNode->parentNode() == rootNode();
  • trunk/Source/WebCore/dom/ChildNodeList.h

    r105408 r123281  
    3939        virtual ~ChildNodeList();
    4040
    41         virtual unsigned length() const;
    42         virtual Node* item(unsigned index) const;
    43 
    4441    protected:
    4542        ChildNodeList(PassRefPtr<Node> rootNode);
  • trunk/Source/WebCore/dom/ClassNodeList.cpp

    r122498 r123281  
    3838
    3939ClassNodeList::ClassNodeList(PassRefPtr<Node> rootNode, const String& classNames)
    40     : DynamicSubtreeNodeList(rootNode, InvalidateOnClassAttrChange)
     40    : DynamicSubtreeNodeList(rootNode, ClassNodeListType, InvalidateOnClassAttrChange)
    4141    , m_classNames(classNames, document()->inQuirksMode())
    4242    , m_originalClassNames(classNames)
  • trunk/Source/WebCore/dom/Document.cpp

    r123248 r123281  
    38833883void Document::registerNodeListCache(DynamicNodeListCacheBase* list)
    38843884{
    3885     if (list->type() != InvalidCollectionType)
     3885    if (list->type() != NodeListCollectionType)
    38863886        m_nodeListCounts[InvalidateOnIdNameAttrChange]++;
    38873887    m_nodeListCounts[list->invalidationType()]++;
     
    38923892void Document::unregisterNodeListCache(DynamicNodeListCacheBase* list)
    38933893{
    3894     if (list->type() != InvalidCollectionType)
     3894    if (list->type() != NodeListCollectionType)
    38953895        m_nodeListCounts[InvalidateOnIdNameAttrChange]--;
    38963896    m_nodeListCounts[list->invalidationType()]--;
  • trunk/Source/WebCore/dom/DynamicNodeList.cpp

    r122621 r123281  
    3737    m_isItemCacheValid = false;
    3838    m_isNameCacheValid = false;
    39     if (type() == InvalidCollectionType)
     39    if (type() == NodeListCollectionType)
    4040        return;
    4141
     
    5252}
    5353
    54 unsigned DynamicSubtreeNodeList::length() const
     54unsigned DynamicNodeList::length() const
    5555{
    56     if (isLengthCacheValid())
    57         return cachedLength();
    58 
    59     unsigned length = 0;
    60     Node* rootNode = this->rootNode();
    61 
    62     for (Node* n = rootNode->firstChild(); n; n = n->traverseNextNode(rootNode))
    63         length += n->isElementNode() && nodeMatches(static_cast<Element*>(n));
    64 
    65     setLengthCache(length);
    66 
    67     return length;
     56    return lengthCommon();
    6857}
    6958
    70 Node* DynamicSubtreeNodeList::itemForwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const
     59Node* DynamicNodeList::item(unsigned offset) const
    7160{
    72     ASSERT(remainingOffset >= 0);
    73     Node* rootNode = this->rootNode();
    74     for (Node* n = start; n; n = n->traverseNextNode(rootNode)) {
    75         if (n->isElementNode() && nodeMatches(static_cast<Element*>(n))) {
    76             if (!remainingOffset) {
    77                 setItemCache(n, offset);
    78                 return n;
    79             }
    80             --remainingOffset;
    81         }
    82     }
    83 
    84     return 0; // no matching node in this subtree
    85 }
    86 
    87 Node* DynamicSubtreeNodeList::itemBackwardsFromCurrent(Node* start, unsigned offset, int remainingOffset) const
    88 {
    89     ASSERT(remainingOffset < 0);
    90     Node* rootNode = this->rootNode();
    91     for (Node* n = start; n; n = n->traversePreviousNode(rootNode)) {
    92         if (n->isElementNode() && nodeMatches(static_cast<Element*>(n))) {
    93             if (!remainingOffset) {
    94                 setItemCache(n, offset);
    95                 return n;
    96             }
    97             ++remainingOffset;
    98         }
    99     }
    100 
    101     return 0; // no matching node in this subtree
    102 }
    103 
    104 Node* DynamicSubtreeNodeList::item(unsigned offset) const
    105 {
    106     int remainingOffset = offset;
    107     Node* start = rootNode()->firstChild();
    108     if (isItemCacheValid()) {
    109         if (offset == cachedItemOffset())
    110             return cachedItem();
    111         if (offset > cachedItemOffset() || cachedItemOffset() - offset < offset) {
    112             start = cachedItem();
    113             remainingOffset -= cachedItemOffset();
    114         }
    115     }
    116 
    117     if (remainingOffset < 0)
    118         return itemBackwardsFromCurrent(start, offset, remainingOffset);
    119     return itemForwardsFromCurrent(start, offset, remainingOffset);
     61    return itemCommon(offset);
    12062}
    12163
  • trunk/Source/WebCore/dom/DynamicNodeList.h

    r122873 r123281  
    4444class DynamicNodeListCacheBase {
    4545public:
    46     enum ItemBeforeSupportType {
    47         DoNotSupportItemBefore,
    48         SupportItemBefore,
     46    enum ItemAfterOverrideType {
     47        OverridesItemAfter,
     48        DoesNotOverrideItemAfter,
    4949    };
    5050
    51     DynamicNodeListCacheBase(NodeListRootType rootType, NodeListInvalidationType invalidationType,
    52         CollectionType collectionType = InvalidCollectionType, ItemBeforeSupportType itemBeforeSupportType = DoNotSupportItemBefore)
    53         : m_cachedItem(0)
     51    DynamicNodeListCacheBase(Node* ownerNode, NodeListRootType rootType, NodeListInvalidationType invalidationType,
     52        bool shouldOnlyIncludeDirectChildren, CollectionType collectionType, ItemAfterOverrideType itemAfterOverrideType)
     53        : m_ownerNode(ownerNode)
     54        , m_cachedItem(0)
    5455        , m_isLengthCacheValid(false)
    5556        , m_isItemCacheValid(false)
    5657        , m_rootedAtDocument(rootType == NodeListIsRootedAtDocument)
    5758        , m_invalidationType(invalidationType)
     59        , m_shouldOnlyIncludeDirectChildren(shouldOnlyIncludeDirectChildren)
    5860        , m_isNameCacheValid(false)
    5961        , m_collectionType(collectionType)
    60         , m_supportsItemBefore(itemBeforeSupportType == SupportItemBefore)
     62        , m_overridesItemAfter(itemAfterOverrideType == OverridesItemAfter)
    6163    {
    6264        ASSERT(m_invalidationType == static_cast<unsigned>(invalidationType));
    6365        ASSERT(m_collectionType == static_cast<unsigned>(collectionType));
     66        ASSERT(!m_overridesItemAfter || m_collectionType != NodeListCollectionType);
    6467    }
    6568
     
    6871    ALWAYS_INLINE NodeListInvalidationType invalidationType() const { return static_cast<NodeListInvalidationType>(m_invalidationType); }
    6972    ALWAYS_INLINE CollectionType type() const { return static_cast<CollectionType>(m_collectionType); }
    70 
     73    Node* ownerNode() const { return m_ownerNode.get(); }
    7174    ALWAYS_INLINE void invalidateCache(const QualifiedName* attrName) const
    7275    {
     
    7982
    8083protected:
    81     bool supportsItemBefore() const { return m_supportsItemBefore; }
     84    Document* document() const { return m_ownerNode->document(); }
     85    Node* rootNode() const
     86    {
     87        if (isRootedAtDocument() && m_ownerNode->inDocument())
     88            return m_ownerNode->document();
     89        return m_ownerNode.get();
     90    }
     91    bool overridesItemAfter() const { return m_overridesItemAfter; }
    8292
    8393    ALWAYS_INLINE bool isItemCacheValid() const { return m_isItemCacheValid; }
    8494    ALWAYS_INLINE Node* cachedItem() const { return m_cachedItem; }
    8595    ALWAYS_INLINE unsigned cachedItemOffset() const { return m_cachedItemOffset; }
     96    unsigned cachedElementsArrayOffset() const;
    8697
    8798    ALWAYS_INLINE bool isLengthCacheValid() const { return m_isLengthCacheValid; }
     
    99110        m_isItemCacheValid = true;
    100111    }
     112    void setItemCache(Node* item, unsigned offset, unsigned elementsArrayOffset) const;
    101113
    102114    bool hasNameCache() const { return m_isNameCacheValid; }
    103115    void setHasNameCache() const { m_isNameCacheValid = true; }
    104116
     117    unsigned lengthCommon() const;
     118    Node* itemCommon(unsigned offset) const;
     119    Node* itemBeforeOrAfterCachedItem(unsigned offset) const;
     120    Node* itemAfter(unsigned&, Node* previousItem) const;
     121
    105122private:
     123    bool shouldOnlyIncludeDirectChildren() const { return m_shouldOnlyIncludeDirectChildren; }
     124    bool isLastItemCloserThanLastOrCachedItem(unsigned offset) const;
     125    bool isFirstItemCloserThanCachedItem(unsigned offset) const;
     126    template <bool forward> Node* iterateForNextNode(Node* current) const;
     127    template<bool forward> Node* itemBeforeOrAfter(Node* previousItem) const;   
     128    Node* itemBefore(Node* previousItem) const;
     129
     130    RefPtr<Node> m_ownerNode;
    106131    mutable Node* m_cachedItem;
    107132    mutable unsigned m_cachedLength;
     
    111136    const unsigned m_rootedAtDocument : 1;
    112137    const unsigned m_invalidationType : 4;
     138    const unsigned m_shouldOnlyIncludeDirectChildren : 1;
    113139
    114140    // From HTMLCollection
    115141    mutable unsigned m_isNameCacheValid : 1;
    116142    const unsigned m_collectionType : 5;
    117     const unsigned m_supportsItemBefore : 1;
     143    const unsigned m_overridesItemAfter : 1;
    118144};
    119145
     
    157183        MicroDataItemListType,
    158184    };
    159     DynamicNodeList(PassRefPtr<Node> ownerNode, NodeListRootType rootType, NodeListInvalidationType invalidationType)
    160         : DynamicNodeListCacheBase(rootType, invalidationType)
    161         , m_ownerNode(ownerNode)
     185    DynamicNodeList(PassRefPtr<Node> ownerNode, NodeListType type, NodeListRootType rootType, NodeListInvalidationType invalidationType)
     186        : DynamicNodeListCacheBase(ownerNode.get(), rootType, invalidationType, type == ChildNodeListType, NodeListCollectionType, DoesNotOverrideItemAfter)
    162187    { }
    163188    virtual ~DynamicNodeList() { }
    164189
    165190    // DOM methods & attributes for NodeList
    166     virtual unsigned length() const = 0;
    167     virtual Node* item(unsigned index) const = 0;
     191    virtual unsigned length() const OVERRIDE;
     192    virtual Node* item(unsigned offset) const OVERRIDE;
    168193    virtual Node* itemWithName(const AtomicString&) const;
    169194
    170195    // Other methods (not part of DOM)
    171     Node* ownerNode() const { return m_ownerNode.get(); }
    172 
    173 protected:
    174     Node* rootNode() const
    175     {
    176         if (isRootedAtDocument() && m_ownerNode->inDocument())
    177             return m_ownerNode->document();
    178         return m_ownerNode.get();
    179     }
    180     Document* document() const { return m_ownerNode->document(); }
    181196    virtual bool nodeMatches(Element*) const = 0;
    182197
    183198private:
    184199    virtual bool isDynamicNodeList() const OVERRIDE { return true; }
    185     RefPtr<Node> m_ownerNode;
    186200};
    187201
     
    192206        document()->unregisterNodeListCache(this);
    193207    }
    194     virtual unsigned length() const OVERRIDE;
    195     virtual Node* item(unsigned index) const OVERRIDE;
    196208
    197209protected:
    198     DynamicSubtreeNodeList(PassRefPtr<Node> node, NodeListInvalidationType invalidationType, NodeListRootType rootType = NodeListIsRootedAtNode)
    199         : DynamicNodeList(node, rootType, invalidationType)
     210    DynamicSubtreeNodeList(PassRefPtr<Node> node, NodeListType type, NodeListInvalidationType invalidationType, NodeListRootType rootType = NodeListIsRootedAtNode)
     211        : DynamicNodeList(node, type, rootType, invalidationType)
    200212    {
    201213        document()->registerNodeListCache(this);
  • trunk/Source/WebCore/dom/MicroDataItemList.cpp

    r122498 r123281  
    4646
    4747MicroDataItemList::MicroDataItemList(PassRefPtr<Node> rootNode, const String& typeNames)
    48     : DynamicSubtreeNodeList(rootNode, InvalidateOnItemAttrChange)
     48    : DynamicSubtreeNodeList(rootNode, MicroDataItemListType, InvalidateOnItemAttrChange)
    4949    , m_typeNames(typeNames, document()->inQuirksMode())
    5050    , m_originalTypeNames(typeNames)
  • trunk/Source/WebCore/dom/NameNodeList.cpp

    r122498 r123281  
    3434
    3535NameNodeList::NameNodeList(PassRefPtr<Node> rootNode, const AtomicString& name)
    36     : DynamicSubtreeNodeList(rootNode, InvalidateOnNameAttrChange)
     36    : DynamicSubtreeNodeList(rootNode, NameNodeListType, InvalidateOnNameAttrChange)
    3737    , m_name(name)
    3838{
  • trunk/Source/WebCore/dom/TagNodeList.cpp

    r122498 r123281  
    3232
    3333TagNodeList::TagNodeList(PassRefPtr<Node> rootNode, const AtomicString& namespaceURI, const AtomicString& localName)
    34     : DynamicSubtreeNodeList(rootNode, DoNotInvalidateOnAttributeChanges)
     34    : DynamicSubtreeNodeList(rootNode, TagNodeListType, DoNotInvalidateOnAttributeChanges)
    3535    , m_namespaceURI(namespaceURI)
    3636    , m_localName(localName)
  • trunk/Source/WebCore/html/CollectionType.h

    r122531 r123281  
    6262
    6363    FormControls,
    64     InvalidCollectionType
     64    NodeListCollectionType
    6565};
    6666
  • trunk/Source/WebCore/html/HTMLAllCollection.cpp

    r122660 r123281  
    3737
    3838HTMLAllCollection::HTMLAllCollection(Document* document)
    39     : HTMLCollection(document, DocAll, SupportItemBefore)
     39    : HTMLCollection(document, DocAll, DoesNotOverrideItemAfter)
    4040{
    4141}
  • trunk/Source/WebCore/html/HTMLCollection.cpp

    r122930 r123281  
    7070    case TableTBodies:
    7171        return true;
    72     case InvalidCollectionType:
     72    case NodeListCollectionType:
    7373        break;
    7474    }
     
    105105    case DataListOptions:
    106106    case MapAreas:
    107     case InvalidCollectionType:
     107    case NodeListCollectionType:
    108108        return NodeListIsRootedAtNode;
    109109    }
     
    145145    case FormControls:
    146146        return InvalidateForFormControls;
    147     case InvalidCollectionType:
     147    case NodeListCollectionType:
    148148        break;
    149149    }
     
    153153   
    154154
    155 HTMLCollection::HTMLCollection(Node* base, CollectionType type, ItemBeforeSupportType itemBeforeSupportType)
    156     : HTMLCollectionCacheBase(rootTypeFromCollectionType(type), invalidationTypeExcludingIdAndNameAttributes(type), type, itemBeforeSupportType)
    157     , m_base(base)
    158 {
    159     ASSERT(m_base);
    160     m_base->document()->registerNodeListCache(this);
     155HTMLCollection::HTMLCollection(Node* ownerNode, CollectionType type, ItemAfterOverrideType itemAfterOverrideType)
     156    : HTMLCollectionCacheBase(ownerNode, rootTypeFromCollectionType(type), invalidationTypeExcludingIdAndNameAttributes(type),
     157        WebCore::shouldOnlyIncludeDirectChildren(type), type, itemAfterOverrideType)
     158{
     159    document()->registerNodeListCache(this);
    161160}
    162161
    163162PassRefPtr<HTMLCollection> HTMLCollection::create(Node* base, CollectionType type)
    164163{
    165     return adoptRef(new HTMLCollection(base, type, SupportItemBefore));
     164    return adoptRef(new HTMLCollection(base, type, DoesNotOverrideItemAfter));
    166165}
    167166
     
    177176        ASSERT(type() == WindowNamedItems || type() == DocumentNamedItems);
    178177
    179     m_base->document()->unregisterNodeListCache(this);
     178    document()->unregisterNodeListCache(this);
    180179}
    181180
     
    232231    case TableRows:
    233232    case WindowNamedItems:
    234     case InvalidCollectionType:
     233    case NodeListCollectionType:
    235234        ASSERT_NOT_REACHED();
    236235    }
     
    255254}
    256255
    257 template<bool forward>
    258 static Element* itemBeforeOrAfter(CollectionType type, Node* base, unsigned& offsetInArray, Node* previous)
    259 {
    260     ASSERT_UNUSED(offsetInArray, !offsetInArray);
    261     bool onlyIncludeDirectChildren = shouldOnlyIncludeDirectChildren(type);
    262     Node* rootNode = base;
     256static Node* firstNode(bool forward, Node* rootNode, bool onlyIncludeDirectChildren)
     257{
     258    if (forward)
     259        return rootNode->firstChild();
     260    else
     261        return onlyIncludeDirectChildren ? rootNode->lastChild() : lastDescendent(rootNode);
     262}
     263
     264template <bool forward>
     265Node* DynamicNodeListCacheBase::iterateForNextNode(Node* current) const
     266{
     267    bool onlyIncludeDirectChildren = shouldOnlyIncludeDirectChildren();
     268    CollectionType collectionType = type();
     269    Node* rootNode = this->rootNode();
     270    for (; current; current = nextNode<forward>(rootNode, current, onlyIncludeDirectChildren)) {
     271        if (collectionType == NodeListCollectionType) {
     272            if (current->isElementNode() && static_cast<const DynamicNodeList*>(this)->nodeMatches(toElement(current)))
     273                return toElement(current);
     274        } else {
     275            if (current->isElementNode() && isAcceptableElement(collectionType, toElement(current)))
     276                return toElement(current);
     277        }
     278    }
     279
     280    return 0;
     281}
     282
     283// Without this ALWAYS_INLINE, length() and item() can be 100% slower.
     284template<bool forward> ALWAYS_INLINE
     285Node* DynamicNodeListCacheBase::itemBeforeOrAfter(Node* previous) const
     286{
    263287    Node* current;
    264     if (previous)
    265         current = nextNode<forward>(rootNode, previous, onlyIncludeDirectChildren);
    266     else {
    267         if (forward)
    268             current = rootNode->firstChild();
    269         else
    270             current = onlyIncludeDirectChildren ? rootNode->lastChild() : lastDescendent(rootNode);
    271     }
    272 
    273     for (; current; current = nextNode<forward>(rootNode, current, onlyIncludeDirectChildren)) {
    274         if (current->isElementNode() && isAcceptableElement(type, toElement(current)))
    275             return toElement(current);
    276     }
    277 
    278     return 0;
    279 }
    280 
    281 Element* HTMLCollection::itemBefore(unsigned& offsetInArray, Element* previous) const
    282 {
    283     return itemBeforeOrAfter<false>(type(), base(), offsetInArray, previous);
    284 }
    285 
    286 Element* HTMLCollection::itemAfter(unsigned& offsetInArray, Element* previous) const
    287 {
    288     return itemBeforeOrAfter<true>(type(), base(), offsetInArray, previous);
    289 }
    290 
    291 bool ALWAYS_INLINE HTMLCollection::isLastItemCloserThanLastOrCachedItem(unsigned offset) const
     288    if (LIKELY(!!previous)) // Without this LIKELY, length() and item() can be 10% slower.
     289        current = nextNode<forward>(rootNode(), previous, shouldOnlyIncludeDirectChildren());
     290    else
     291        current = firstNode(forward, rootNode(), previous);
     292
     293    if (type() == NodeListCollectionType && shouldOnlyIncludeDirectChildren()) // ChildNodeList
     294        return current;
     295
     296    return iterateForNextNode<forward>(current);
     297}
     298
     299// Without this ALWAYS_INLINE, length() and item() can be 100% slower.
     300ALWAYS_INLINE Node* DynamicNodeListCacheBase::itemBefore(Node* previous) const
     301{
     302    return itemBeforeOrAfter<false>(previous);
     303}
     304
     305// Without this ALWAYS_INLINE, length() and item() can be 100% slower.
     306ALWAYS_INLINE Node* DynamicNodeListCacheBase::itemAfter(unsigned& offsetInArray, Node* previous) const
     307{
     308    if (UNLIKELY(overridesItemAfter())) // Without this UNLIKELY, length() can be 100% slower.
     309        return static_cast<const HTMLCollection*>(this)->virtualItemAfter(offsetInArray, toElement(previous));
     310    ASSERT(!offsetInArray);
     311    return itemBeforeOrAfter<true>(previous);
     312}
     313
     314bool ALWAYS_INLINE DynamicNodeListCacheBase::isLastItemCloserThanLastOrCachedItem(unsigned offset) const
    292315{
    293316    ASSERT(isLengthCacheValid());
     
    299322}
    300323   
    301 bool ALWAYS_INLINE HTMLCollection::isFirstItemCloserThanCachedItem(unsigned offset) const
     324bool ALWAYS_INLINE DynamicNodeListCacheBase::isFirstItemCloserThanCachedItem(unsigned offset) const
    302325{
    303326    ASSERT(isItemCacheValid());
     
    309332}
    310333
    311 unsigned HTMLCollection::length() const
     334ALWAYS_INLINE void DynamicNodeListCacheBase::setItemCache(Node* item, unsigned offset, unsigned elementsArrayOffset) const
     335{
     336    setItemCache(item, offset);
     337    if (overridesItemAfter()) {
     338        ASSERT(item->isElementNode());
     339        static_cast<const HTMLCollectionCacheBase*>(this)->m_cachedElementsArrayOffset = elementsArrayOffset;
     340    } else
     341        ASSERT(!elementsArrayOffset);
     342}
     343
     344ALWAYS_INLINE unsigned DynamicNodeListCacheBase::cachedElementsArrayOffset() const
     345{
     346    return overridesItemAfter() ? static_cast<const HTMLCollectionCacheBase*>(this)->m_cachedElementsArrayOffset : 0;
     347}
     348
     349unsigned DynamicNodeListCacheBase::lengthCommon() const
    312350{
    313351    if (isLengthCacheValid())
    314352        return cachedLength();
    315353
    316     if (!isItemCacheValid() && !item(0)) {
    317         ASSERT(isLengthCacheValid());
    318         return 0;
    319     }
    320 
    321     ASSERT(isItemCacheValid());
    322     ASSERT(cachedItem());
    323     unsigned offset = cachedItemOffset();
    324     do {
    325         offset++;
    326     } while (itemBeforeOrAfterCachedItem(offset));
     354    itemCommon(UINT_MAX);
    327355    ASSERT(isLengthCacheValid());
    328 
    329     return offset;
    330 }
    331 
    332 Node* HTMLCollection::item(unsigned offset) const
     356   
     357    return cachedLength();
     358}
     359
     360Node* DynamicNodeListCacheBase::itemCommon(unsigned offset) const
    333361{
    334362    if (isItemCacheValid() && cachedItemOffset() == offset)
     
    343371#endif
    344372
    345     if (isLengthCacheValid() && supportsItemBefore() && isLastItemCloserThanLastOrCachedItem(offset)) {
    346         // FIXME: Need to figure out the last offset in array for HTMLFormCollection and HTMLPropertiesCollection
    347         unsigned unusedOffsetInArray = 0;
    348         Node* lastItem = itemBefore(unusedOffsetInArray, 0);
    349         ASSERT(!unusedOffsetInArray);
     373    if (isLengthCacheValid() && !overridesItemAfter() && isLastItemCloserThanLastOrCachedItem(offset)) {
     374        Node* lastItem = itemBefore(0);
    350375        ASSERT(lastItem);
    351376        setItemCache(lastItem, cachedLength() - 1, 0);
    352     } else if (!isItemCacheValid() || isFirstItemCloserThanCachedItem(offset) || (!supportsItemBefore() && offset < cachedItemOffset())) {
     377    } else if (!isItemCacheValid() || isFirstItemCloserThanCachedItem(offset) || (overridesItemAfter() && offset < cachedItemOffset())) {
    353378        unsigned offsetInArray = 0;
    354379        Node* firstItem = itemAfter(offsetInArray, 0);
     
    367392}
    368393
    369 Element* HTMLCollection::itemBeforeOrAfterCachedItem(unsigned offset) const
     394Node* DynamicNodeListCacheBase::itemBeforeOrAfterCachedItem(unsigned offset) const
    370395{
    371396    unsigned currentOffset = cachedItemOffset();
    372     ASSERT(cachedItem()->isElementNode());
    373     Element* currentItem = toElement(cachedItem());
     397    Node* currentItem = cachedItem();
    374398    ASSERT(currentOffset != offset);
    375399
    376     unsigned offsetInArray = cachedElementsArrayOffset();
    377 
    378400    if (offset < cachedItemOffset()) {
    379         ASSERT(supportsItemBefore());
    380         while ((currentItem = itemBefore(offsetInArray, currentItem))) {
     401        ASSERT(!overridesItemAfter());
     402        while ((currentItem = itemBefore(currentItem))) {
    381403            ASSERT(currentOffset);
    382404            currentOffset--;
    383405            if (currentOffset == offset) {
    384                 setItemCache(currentItem, currentOffset, offsetInArray);
     406                setItemCache(currentItem, currentOffset, 0);
    385407                return currentItem;
    386408            }
     
    390412    }
    391413
     414    unsigned offsetInArray = cachedElementsArrayOffset();
    392415    while ((currentItem = itemAfter(offsetInArray, currentItem))) {
    393416        currentOffset++;
     
    401424    setLengthCache(offsetOfLastItem + 1);
    402425
     426    return 0;
     427}
     428
     429Element* HTMLCollection::virtualItemAfter(unsigned&, Element*) const
     430{
     431    ASSERT_NOT_REACHED();
    403432    return 0;
    404433}
     
    442471    unsigned arrayOffset = 0;
    443472    unsigned i = 0;
    444     for (Element* e = itemAfter(arrayOffset, 0); e; e = itemAfter(arrayOffset, e)) {
    445         if (checkForNameMatch(e, /* checkName */ false, name)) {
     473    for (Node* e = itemAfter(arrayOffset, 0); e; e = itemAfter(arrayOffset, e)) {
     474        if (checkForNameMatch(toElement(e), /* checkName */ false, name)) {
    446475            setItemCache(e, i, arrayOffset);
    447476            return e;
     
    451480
    452481    i = 0;
    453     for (Element* e = itemAfter(arrayOffset, 0); e; e = itemAfter(arrayOffset, e)) {
    454         if (checkForNameMatch(e, /* checkName */ true, name)) {
     482    for (Node* e = itemAfter(arrayOffset, 0); e; e = itemAfter(arrayOffset, e)) {
     483        if (checkForNameMatch(toElement(e), /* checkName */ true, name)) {
    455484            setItemCache(e, i, arrayOffset);
    456             return e;
     485            return toElement(e);
    457486        }
    458487        i++;
     
    468497
    469498    unsigned arrayOffset = 0;
    470     for (Element* element = itemAfter(arrayOffset, 0); element; element = itemAfter(arrayOffset, element)) {
    471         if (!element->isHTMLElement())
     499    for (Node* node = itemAfter(arrayOffset, 0); node; node = itemAfter(arrayOffset, node)) {
     500        if (!node->isHTMLElement())
    472501            continue;
    473         HTMLElement* e = toHTMLElement(element);
     502        HTMLElement* e = toHTMLElement(node);
    474503        const AtomicString& idAttrVal = e->getIdAttribute();
    475504        const AtomicString& nameAttrVal = e->getNameAttribute();
     
    523552PassRefPtr<NodeList> HTMLCollection::tags(const String& name)
    524553{
    525     return m_base->getElementsByTagName(name);
     554    return ownerNode()->getElementsByTagName(name);
    526555}
    527556
  • trunk/Source/WebCore/html/HTMLCollection.h

    r122672 r123281  
    4040class HTMLCollectionCacheBase : public DynamicNodeListCacheBase {
    4141public:
    42     HTMLCollectionCacheBase(NodeListRootType rootType, NodeListInvalidationType invalidationType, CollectionType collectionType, ItemBeforeSupportType itemBeforeSupportType)
    43         : DynamicNodeListCacheBase(rootType, invalidationType, collectionType, itemBeforeSupportType)
    44         , m_cachedElementsArrayOffset(0)
     42    HTMLCollectionCacheBase(Node* ownerNode, NodeListRootType rootType, NodeListInvalidationType invalidationType,
     43        bool shouldOnlyIncludeDirectChildren, CollectionType collectionType, ItemAfterOverrideType itemAfterOverrideType)
     44        : DynamicNodeListCacheBase(ownerNode, rootType, invalidationType, shouldOnlyIncludeDirectChildren, collectionType, itemAfterOverrideType)
    4545    {
    4646    }
    4747
    4848protected:
    49     void setItemCache(Node* item, unsigned offset, unsigned elementsArrayOffset) const
    50     {
    51         setItemCache(item, offset);
    52         m_cachedElementsArrayOffset = elementsArrayOffset;
    53     }
    54     unsigned cachedElementsArrayOffset() const { return m_cachedElementsArrayOffset; }
    55 
    5649    typedef HashMap<AtomicStringImpl*, OwnPtr<Vector<Element*> > > NodeCacheMap;
    5750    Vector<Element*>* idCache(const AtomicString& name) const { return m_idCache.get(name.impl()); }
     
    6457private:
    6558    using DynamicNodeListCacheBase::isRootedAtDocument;
    66     using DynamicNodeListCacheBase::setItemCache;
    6759
    6860    mutable NodeCacheMap m_idCache;
     
    7062    mutable unsigned m_cachedElementsArrayOffset;
    7163
    72     friend void DynamicNodeListCacheBase::invalidateCache() const;
     64    friend class DynamicNodeListCacheBase;
    7365};
    7466
     
    7971
    8072    // DOM API
    81     unsigned length() const;
    82     Node* item(unsigned index) const;
     73    unsigned length() const { return lengthCommon(); }
     74    Node* item(unsigned offset) const { return itemCommon(offset); }
    8375    virtual Node* namedItem(const AtomicString& name) const;
    8476    PassRefPtr<NodeList> tags(const String&);
     
    10496    }
    10597
    106     Node* base() const { return m_base.get(); }
     98    Node* base() const { return ownerNode(); }
     99    virtual Element* virtualItemAfter(unsigned& offsetInArray, Element*) const;
    107100
    108101protected:
    109     HTMLCollection(Node* base, CollectionType, ItemBeforeSupportType);
     102    HTMLCollection(Node* base, CollectionType, ItemAfterOverrideType);
    110103
    111104    virtual void updateNameCache() const;
    112     virtual Element* itemAfter(unsigned& offsetInArray, Element*) const;
    113105
    114106private:
    115107    bool checkForNameMatch(Element*, bool checkName, const AtomicString& name) const;
    116 
    117     Element* itemBefore(unsigned& offsetInArray, Element*) const;
    118     bool isLastItemCloserThanLastOrCachedItem(unsigned offset) const;
    119     bool isFirstItemCloserThanCachedItem(unsigned offset) const;
    120     Element* itemBeforeOrAfterCachedItem(unsigned offset) const;
    121 
    122     RefPtr<Node> m_base;
    123108};
    124109
  • trunk/Source/WebCore/html/HTMLFormCollection.cpp

    r122660 r123281  
    3838
    3939HTMLFormCollection::HTMLFormCollection(Element* base)
    40     : HTMLCollection(base, FormControls, DoNotSupportItemBefore)
     40    : HTMLCollection(base, FormControls, OverridesItemAfter)
    4141{
    4242    ASSERT(base->hasTagName(formTag) || base->hasTagName(fieldsetTag));
     
    6868}
    6969
    70 Element* HTMLFormCollection::itemAfter(unsigned& offset, Element* previousItem) const
     70Element* HTMLFormCollection::virtualItemAfter(unsigned& offset, Element* previousItem) const
    7171{
    7272    const Vector<FormAssociatedElement*>& elementsArray = formControlElements();
  • trunk/Source/WebCore/html/HTMLFormCollection.h

    r122518 r123281  
    5050    const Vector<FormAssociatedElement*>& formControlElements() const;
    5151    const Vector<HTMLImageElement*>& formImageElements() const;
    52     virtual Element* itemAfter(unsigned& offsetInArray, Element*) const OVERRIDE;
     52    virtual Element* virtualItemAfter(unsigned& offsetInArray, Element*) const OVERRIDE;
    5353};
    5454
  • trunk/Source/WebCore/html/HTMLNameCollection.cpp

    r122660 r123281  
    3434
    3535HTMLNameCollection::HTMLNameCollection(Document* document, CollectionType type, const AtomicString& name)
    36     : HTMLCollection(document, type, DoNotSupportItemBefore)
     36    : HTMLCollection(document, type, OverridesItemAfter)
    3737    , m_name(name)
    3838{
     
    5050}
    5151
    52 Element* HTMLNameCollection::itemAfter(unsigned& offsetInArray, Element* previous) const
     52Element* HTMLNameCollection::virtualItemAfter(unsigned& offsetInArray, Element* previous) const
    5353{
    5454    ASSERT_UNUSED(offsetInArray, !offsetInArray);
  • trunk/Source/WebCore/html/HTMLNameCollection.h

    r122518 r123281  
    4444    HTMLNameCollection(Document*, CollectionType, const AtomicString& name);
    4545
    46     virtual Element* itemAfter(unsigned& offsetInArray, Element*) const OVERRIDE;
     46    virtual Element* virtualItemAfter(unsigned& offsetInArray, Element*) const OVERRIDE;
    4747
    4848    AtomicString m_name;
  • trunk/Source/WebCore/html/HTMLOptionsCollection.cpp

    r122660 r123281  
    2929
    3030HTMLOptionsCollection::HTMLOptionsCollection(Element* select)
    31     : HTMLCollection(select, SelectOptions, SupportItemBefore)
     31    : HTMLCollection(select, SelectOptions, DoesNotOverrideItemAfter)
    3232{
    3333    ASSERT(select->hasTagName(HTMLNames::selectTag));
  • trunk/Source/WebCore/html/HTMLPropertiesCollection.cpp

    r122660 r123281  
    5252
    5353HTMLPropertiesCollection::HTMLPropertiesCollection(Node* itemNode)
    54     : HTMLCollection(itemNode, ItemProperties, DoNotSupportItemBefore)
     54    : HTMLCollection(itemNode, ItemProperties, OverridesItemAfter)
    5555    , m_hasPropertyNameCache(false)
    5656    , m_hasItemRefElements(false)
     
    113113}
    114114
    115 Element* HTMLPropertiesCollection::itemAfter(unsigned& offsetInArray, Element* previousItem) const
     115Element* HTMLPropertiesCollection::virtualItemAfter(unsigned& offsetInArray, Element* previousItem) const
    116116{
    117117    while (offsetInArray < m_itemRefElements.size()) {
    118         if (Element* next = itemAfter(m_itemRefElements[offsetInArray], previousItem))
     118        if (Element* next = virtualItemAfter(m_itemRefElements[offsetInArray], previousItem))
    119119            return next;
    120120        offsetInArray++;
     
    124124}
    125125
    126 HTMLElement* HTMLPropertiesCollection::itemAfter(HTMLElement* base, Element* previous) const
     126HTMLElement* HTMLPropertiesCollection::virtualItemAfter(HTMLElement* base, Element* previous) const
    127127{
    128128    Node* current;
     
    150150    for (unsigned i = 0; i < m_itemRefElements.size(); ++i) {
    151151        HTMLElement* refElement = m_itemRefElements[i];
    152         for (HTMLElement* element = itemAfter(refElement, 0); element; element = itemAfter(refElement, element)) {
     152        for (HTMLElement* element = virtualItemAfter(refElement, 0); element; element = virtualItemAfter(refElement, element)) {
    153153            DOMSettableTokenList* itemProperty = element->itemProp();
    154154            for (unsigned propertyIndex = 0; propertyIndex < itemProperty->length(); ++propertyIndex)
  • trunk/Source/WebCore/html/HTMLPropertiesCollection.h

    r122621 r123281  
    6666    Node* findRefElements(Node* previous) const;
    6767
    68     virtual Element* itemAfter(unsigned& offsetInArray, Element*) const OVERRIDE;
    69     HTMLElement* itemAfter(HTMLElement* base, Element* previous) const;
     68    virtual Element* virtualItemAfter(unsigned& offsetInArray, Element*) const OVERRIDE;
     69    HTMLElement* virtualItemAfter(HTMLElement* base, Element* previous) const;
    7070
    7171    void updateNameCache() const;
  • trunk/Source/WebCore/html/HTMLTableRowsCollection.cpp

    r122660 r123281  
    153153// differ between compilers.
    154154HTMLTableRowsCollection::HTMLTableRowsCollection(Element* table)
    155     : HTMLCollection(table, TableRows, DoNotSupportItemBefore)
     155    : HTMLCollection(table, TableRows, OverridesItemAfter)
    156156{
    157157    ASSERT(table->hasTagName(tableTag));
     
    163163}
    164164
    165 Element* HTMLTableRowsCollection::itemAfter(unsigned& offsetInArray, Element* previous) const
     165Element* HTMLTableRowsCollection::virtualItemAfter(unsigned& offsetInArray, Element* previous) const
    166166{
    167167    ASSERT_UNUSED(offsetInArray, !offsetInArray);
  • trunk/Source/WebCore/html/HTMLTableRowsCollection.h

    r122518 r123281  
    4747    HTMLTableRowsCollection(Element*);
    4848
    49     virtual Element* itemAfter(unsigned& offsetInArray, Element*) const OVERRIDE;
     49    virtual Element* virtualItemAfter(unsigned& offsetInArray, Element*) const OVERRIDE;
    5050};
    5151
  • trunk/Source/WebCore/html/LabelsNodeList.cpp

    r122498 r123281  
    3535
    3636LabelsNodeList::LabelsNodeList(Node* forNode)
    37     : DynamicSubtreeNodeList(forNode, InvalidateOnForAttrChange, NodeListIsRootedAtDocument)
     37    : DynamicSubtreeNodeList(forNode, LabelsNodeListType, InvalidateOnForAttrChange, NodeListIsRootedAtDocument)
    3838{
    3939}
  • trunk/Source/WebCore/html/RadioNodeList.cpp

    r122546 r123281  
    3939
    4040RadioNodeList::RadioNodeList(Node* rootNode, const AtomicString& name)
    41     : DynamicSubtreeNodeList(rootNode, InvalidateForFormControls, rootNode->hasTagName(formTag) ? NodeListIsRootedAtDocument : NodeListIsRootedAtNode)
     41    : DynamicSubtreeNodeList(rootNode, RadioNodeListType, InvalidateForFormControls, rootNode->hasTagName(formTag) ? NodeListIsRootedAtDocument : NodeListIsRootedAtNode)
    4242    , m_name(name)
    4343{
Note: See TracChangeset for help on using the changeset viewer.