Commit 7610004e authored by ch.dumez@samsung.com's avatar ch.dumez@samsung.com

Move matching Element traversal functions from LiveNodeListBase to ElementTraversal

Move matching Element traversal functions from LiveNodeListBase to
ElementTraversal and generalized them a bit so that they can be reused in the
rest of the code base.

LiveNodeListBase exists so that code can be shared between LiveNodeList and
HTMLCollection. However, the ElementTraversal class is a better place to share
DOM Tree traversal utility functions. It is quite common in the code base that
we want to traverse Elements that match a specific rule so this will reduce
code duplication once the rest of the code is ported to these new
ElementTraversal functions.

R=adamk@chromium.org, esprehn@chromium.org

Review URL: https://codereview.chromium.org/468183002

git-svn-id: svn://svn.chromium.org/blink/trunk@180227 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 6d9bba7b
...@@ -37,8 +37,12 @@ public: ...@@ -37,8 +37,12 @@ public:
// First or last ElementType child of the node. // First or last ElementType child of the node.
static ElementType* firstChild(const ContainerNode& current) { return firstChildTemplate(current); } static ElementType* firstChild(const ContainerNode& current) { return firstChildTemplate(current); }
static ElementType* firstChild(const Node& current) { return firstChildTemplate(current); } static ElementType* firstChild(const Node& current) { return firstChildTemplate(current); }
template <class MatchFunc>
static ElementType* firstChild(const ContainerNode&, MatchFunc);
static ElementType* lastChild(const ContainerNode& current) { return lastChildTemplate(current); } static ElementType* lastChild(const ContainerNode& current) { return lastChildTemplate(current); }
static ElementType* lastChild(const Node& current) { return lastChildTemplate(current); } static ElementType* lastChild(const Node& current) { return lastChildTemplate(current); }
template <class MatchFunc>
static ElementType* lastChild(const ContainerNode&, MatchFunc);
// First ElementType ancestor of the node. // First ElementType ancestor of the node.
static ElementType* firstAncestor(const Node& current); static ElementType* firstAncestor(const Node& current);
...@@ -51,16 +55,24 @@ public: ...@@ -51,16 +55,24 @@ public:
// For Elements firstWithin() is always the same as firstChild(). // For Elements firstWithin() is always the same as firstChild().
static ElementType* firstWithin(const ContainerNode& current) { return firstWithinTemplate(current); } static ElementType* firstWithin(const ContainerNode& current) { return firstWithinTemplate(current); }
static ElementType* firstWithin(const Node& current) { return firstWithinTemplate(current); } static ElementType* firstWithin(const Node& current) { return firstWithinTemplate(current); }
template <typename MatchFunc>
static ElementType* firstWithin(const ContainerNode&, MatchFunc);
static ElementType* lastWithin(const ContainerNode& current) { return lastWithinTemplate(current); } static ElementType* lastWithin(const ContainerNode& current) { return lastWithinTemplate(current); }
static ElementType* lastWithin(const Node& current) { return lastWithinTemplate(current); } static ElementType* lastWithin(const Node& current) { return lastWithinTemplate(current); }
template <class MatchFunc>
static ElementType* lastWithin(const ContainerNode&, MatchFunc);
// Pre-order traversal skipping non-element nodes. // Pre-order traversal skipping non-element nodes.
static ElementType* next(const ContainerNode& current) { return nextTemplate(current); } static ElementType* next(const ContainerNode& current) { return nextTemplate(current); }
static ElementType* next(const Node& current) { return nextTemplate(current); } static ElementType* next(const Node& current) { return nextTemplate(current); }
static ElementType* next(const ContainerNode& current, const Node* stayWithin) { return nextTemplate(current, stayWithin); } static ElementType* next(const ContainerNode& current, const Node* stayWithin) { return nextTemplate(current, stayWithin); }
static ElementType* next(const Node& current, const Node* stayWithin) { return nextTemplate(current, stayWithin); } static ElementType* next(const Node& current, const Node* stayWithin) { return nextTemplate(current, stayWithin); }
template <class MatchFunc>
static ElementType* next(const ContainerNode& current, const Node* stayWithin, MatchFunc);
static ElementType* previous(const Node&); static ElementType* previous(const Node&);
static ElementType* previous(const Node&, const Node* stayWithin); static ElementType* previous(const Node&, const Node* stayWithin);
template <class MatchFunc>
static ElementType* previous(const ContainerNode& current, const Node* stayWithin, MatchFunc);
// Like next, but skips children. // Like next, but skips children.
static ElementType* nextSkippingChildren(const Node&); static ElementType* nextSkippingChildren(const Node&);
...@@ -76,7 +88,11 @@ public: ...@@ -76,7 +88,11 @@ public:
// Previous / Next sibling. // Previous / Next sibling.
static ElementType* previousSibling(const Node&); static ElementType* previousSibling(const Node&);
template <class MatchFunc>
static ElementType* previousSibling(const Node&, MatchFunc);
static ElementType* nextSibling(const Node&); static ElementType* nextSibling(const Node&);
template <class MatchFunc>
static ElementType* nextSibling(const Node&, MatchFunc);
private: private:
template <class NodeType> template <class NodeType>
...@@ -136,6 +152,16 @@ inline ElementType* Traversal<ElementType>::firstChildTemplate(NodeType& current ...@@ -136,6 +152,16 @@ inline ElementType* Traversal<ElementType>::firstChildTemplate(NodeType& current
return toElement<ElementType>(node); return toElement<ElementType>(node);
} }
template <class ElementType>
template <class MatchFunc>
inline ElementType* Traversal<ElementType>::firstChild(const ContainerNode& current, MatchFunc isMatch)
{
ElementType* element = Traversal<ElementType>::firstChild(current);
while (element && !isMatch(*element))
element = Traversal<ElementType>::nextSibling(*element);
return element;
}
template <class ElementType> template <class ElementType>
inline ElementType* Traversal<ElementType>::firstAncestor(const Node& current) inline ElementType* Traversal<ElementType>::firstAncestor(const Node& current)
{ {
...@@ -164,6 +190,16 @@ inline ElementType* Traversal<ElementType>::lastChildTemplate(NodeType& current) ...@@ -164,6 +190,16 @@ inline ElementType* Traversal<ElementType>::lastChildTemplate(NodeType& current)
return toElement<ElementType>(node); return toElement<ElementType>(node);
} }
template <class ElementType>
template <class MatchFunc>
inline ElementType* Traversal<ElementType>::lastChild(const ContainerNode& current, MatchFunc isMatch)
{
ElementType* element = Traversal<ElementType>::lastChild(current);
while (element && !isMatch(*element))
element = Traversal<ElementType>::previousSibling(*element);
return element;
}
template <class ElementType> template <class ElementType>
template <class NodeType> template <class NodeType>
inline ElementType* Traversal<ElementType>::firstWithinTemplate(NodeType& current) inline ElementType* Traversal<ElementType>::firstWithinTemplate(NodeType& current)
...@@ -174,6 +210,16 @@ inline ElementType* Traversal<ElementType>::firstWithinTemplate(NodeType& curren ...@@ -174,6 +210,16 @@ inline ElementType* Traversal<ElementType>::firstWithinTemplate(NodeType& curren
return toElement<ElementType>(node); return toElement<ElementType>(node);
} }
template <class ElementType>
template <typename MatchFunc>
inline ElementType* Traversal<ElementType>::firstWithin(const ContainerNode& current, MatchFunc isMatch)
{
ElementType* element = Traversal<ElementType>::firstWithin(current);
while (element && !isMatch(*element))
element = Traversal<ElementType>::next(*element, &current, isMatch);
return element;
}
template <class ElementType> template <class ElementType>
template <class NodeType> template <class NodeType>
inline ElementType* Traversal<ElementType>::lastWithinTemplate(NodeType& current) inline ElementType* Traversal<ElementType>::lastWithinTemplate(NodeType& current)
...@@ -184,6 +230,16 @@ inline ElementType* Traversal<ElementType>::lastWithinTemplate(NodeType& current ...@@ -184,6 +230,16 @@ inline ElementType* Traversal<ElementType>::lastWithinTemplate(NodeType& current
return toElement<ElementType>(node); return toElement<ElementType>(node);
} }
template <class ElementType>
template <class MatchFunc>
inline ElementType* Traversal<ElementType>::lastWithin(const ContainerNode& current, MatchFunc isMatch)
{
ElementType* element = Traversal<ElementType>::lastWithin(current);
while (element && !isMatch(*element))
element = Traversal<ElementType>::previous(*element, &current, isMatch);
return element;
}
template <class ElementType> template <class ElementType>
template <class NodeType> template <class NodeType>
inline ElementType* Traversal<ElementType>::nextTemplate(NodeType& current) inline ElementType* Traversal<ElementType>::nextTemplate(NodeType& current)
...@@ -204,6 +260,16 @@ inline ElementType* Traversal<ElementType>::nextTemplate(NodeType& current, cons ...@@ -204,6 +260,16 @@ inline ElementType* Traversal<ElementType>::nextTemplate(NodeType& current, cons
return toElement<ElementType>(node); return toElement<ElementType>(node);
} }
template <class ElementType>
template <class MatchFunc>
inline ElementType* Traversal<ElementType>::next(const ContainerNode& current, const Node* stayWithin, MatchFunc isMatch)
{
ElementType* element = Traversal<ElementType>::next(current, stayWithin);
while (element && !isMatch(*element))
element = Traversal<ElementType>::next(*element, stayWithin);
return element;
}
template <class ElementType> template <class ElementType>
inline ElementType* Traversal<ElementType>::previous(const Node& current) inline ElementType* Traversal<ElementType>::previous(const Node& current)
{ {
...@@ -222,6 +288,16 @@ inline ElementType* Traversal<ElementType>::previous(const Node& current, const ...@@ -222,6 +288,16 @@ inline ElementType* Traversal<ElementType>::previous(const Node& current, const
return toElement<ElementType>(node); return toElement<ElementType>(node);
} }
template <class ElementType>
template <class MatchFunc>
inline ElementType* Traversal<ElementType>::previous(const ContainerNode& current, const Node* stayWithin, MatchFunc isMatch)
{
ElementType* element = Traversal<ElementType>::previous(current, stayWithin);
while (element && !isMatch(*element))
element = Traversal<ElementType>::previous(*element, stayWithin);
return element;
}
template <class ElementType> template <class ElementType>
inline ElementType* Traversal<ElementType>::nextSkippingChildren(const Node& current) inline ElementType* Traversal<ElementType>::nextSkippingChildren(const Node& current)
{ {
...@@ -285,6 +361,16 @@ inline ElementType* Traversal<ElementType>::previousSibling(const Node& current) ...@@ -285,6 +361,16 @@ inline ElementType* Traversal<ElementType>::previousSibling(const Node& current)
return toElement<ElementType>(node); return toElement<ElementType>(node);
} }
template <class ElementType>
template <class MatchFunc>
inline ElementType* Traversal<ElementType>::previousSibling(const Node& current, MatchFunc isMatch)
{
ElementType* element = Traversal<ElementType>::previousSibling(current);
while (element && !isMatch(*element))
element = Traversal<ElementType>::previousSibling(*element);
return element;
}
template <class ElementType> template <class ElementType>
inline ElementType* Traversal<ElementType>::nextSibling(const Node& current) inline ElementType* Traversal<ElementType>::nextSibling(const Node& current)
{ {
...@@ -294,6 +380,16 @@ inline ElementType* Traversal<ElementType>::nextSibling(const Node& current) ...@@ -294,6 +380,16 @@ inline ElementType* Traversal<ElementType>::nextSibling(const Node& current)
return toElement<ElementType>(node); return toElement<ElementType>(node);
} }
template <class ElementType>
template <class MatchFunc>
inline ElementType* Traversal<ElementType>::nextSibling(const Node& current, MatchFunc isMatch)
{
ElementType* element = Traversal<ElementType>::nextSibling(current);
while (element && !isMatch(*element))
element = Traversal<ElementType>::nextSibling(*element);
return element;
}
} // namespace blink } // namespace blink
#endif #endif
...@@ -25,10 +25,24 @@ ...@@ -25,10 +25,24 @@
namespace blink { namespace blink {
static inline bool isMatchingElement(const LiveNodeList& nodeList, const Element& element) namespace {
{
return nodeList.elementMatches(element); class IsMatch {
} public:
IsMatch(const LiveNodeList& list)
: m_list(list)
{ }
bool operator() (const Element& element) const
{
return m_list.elementMatches(element);
}
private:
const LiveNodeList& m_list;
};
} // namespace
Node* LiveNodeList::virtualOwnerNode() const Node* LiveNodeList::virtualOwnerNode() const
{ {
...@@ -52,22 +66,22 @@ Element* LiveNodeList::item(unsigned offset) const ...@@ -52,22 +66,22 @@ Element* LiveNodeList::item(unsigned offset) const
Element* LiveNodeList::traverseToFirstElement() const Element* LiveNodeList::traverseToFirstElement() const
{ {
return firstMatchingElement(*this); return ElementTraversal::firstWithin(rootNode(), IsMatch(*this));
} }
Element* LiveNodeList::traverseToLastElement() const Element* LiveNodeList::traverseToLastElement() const
{ {
return lastMatchingElement(*this); return ElementTraversal::lastWithin(rootNode(), IsMatch(*this));
} }
Element* LiveNodeList::traverseForwardToOffset(unsigned offset, Element& currentNode, unsigned& currentOffset) const Element* LiveNodeList::traverseForwardToOffset(unsigned offset, Element& currentElement, unsigned& currentOffset) const
{ {
return traverseMatchingElementsForwardToOffset(*this, offset, currentNode, currentOffset); return traverseMatchingElementsForwardToOffset(currentElement, &rootNode(), offset, currentOffset, IsMatch(*this));
} }
Element* LiveNodeList::traverseBackwardToOffset(unsigned offset, Element& currentNode, unsigned& currentOffset) const Element* LiveNodeList::traverseBackwardToOffset(unsigned offset, Element& currentElement, unsigned& currentOffset) const
{ {
return traverseMatchingElementsBackwardToOffset(*this, offset, currentNode, currentOffset); return traverseMatchingElementsBackwardToOffset(currentElement, &rootNode(), offset, currentOffset, IsMatch(*this));
} }
void LiveNodeList::trace(Visitor* visitor) void LiveNodeList::trace(Visitor* visitor)
......
...@@ -79,18 +79,10 @@ protected: ...@@ -79,18 +79,10 @@ protected:
ALWAYS_INLINE NodeListRootType rootType() const { return static_cast<NodeListRootType>(m_rootType); } ALWAYS_INLINE NodeListRootType rootType() const { return static_cast<NodeListRootType>(m_rootType); }
template <class NodeListType> template <typename MatchFunc>
static Element* firstMatchingElement(const NodeListType&); static Element* traverseMatchingElementsForwardToOffset(Element& currentElement, const ContainerNode* stayWithin, unsigned offset, unsigned& currentOffset, MatchFunc);
template <class NodeListType> template <typename MatchFunc>
static Element* lastMatchingElement(const NodeListType&); static Element* traverseMatchingElementsBackwardToOffset(Element& currentElement, const ContainerNode* stayWithin, unsigned offset, unsigned& currentOffset, MatchFunc);
template <class NodeListType>
static Element* nextMatchingElement(const NodeListType&, Element& current);
template <class NodeListType>
static Element* previousMatchingElement(const NodeListType&, Element& current);
template <class NodeListType>
static Element* traverseMatchingElementsForwardToOffset(const NodeListType&, unsigned offset, Element& currentElement, unsigned& currentOffset);
template <class NodeListType>
static Element* traverseMatchingElementsBackwardToOffset(const NodeListType&, unsigned offset, Element& currentElement, unsigned& currentOffset);
virtual void trace(Visitor* visitor) { visitor->trace(m_ownerNode); } virtual void trace(Visitor* visitor) { visitor->trace(m_ownerNode); }
...@@ -125,64 +117,22 @@ ALWAYS_INLINE bool LiveNodeListBase::shouldInvalidateTypeOnAttributeChange(NodeL ...@@ -125,64 +117,22 @@ ALWAYS_INLINE bool LiveNodeListBase::shouldInvalidateTypeOnAttributeChange(NodeL
return false; return false;
} }
template <typename NodeListType> template <typename MatchFunc>
Element* LiveNodeListBase::lastMatchingElement(const NodeListType& nodeList) Element* LiveNodeListBase::traverseMatchingElementsForwardToOffset(Element& currentElement, const ContainerNode* stayWithin, unsigned offset, unsigned& currentOffset, MatchFunc isMatch)
{
ContainerNode& root = nodeList.rootNode();
Element* element = ElementTraversal::lastWithin(root);
while (element && !isMatchingElement(nodeList, *element))
element = ElementTraversal::previous(*element, &root);
return element;
}
template <class NodeListType>
Element* LiveNodeListBase::firstMatchingElement(const NodeListType& nodeList)
{
ContainerNode& root = nodeList.rootNode();
Element* element = ElementTraversal::firstWithin(root);
while (element && !isMatchingElement(nodeList, *element))
element = ElementTraversal::next(*element, &root);
return element;
}
template <class NodeListType>
Element* LiveNodeListBase::nextMatchingElement(const NodeListType& nodeList, Element& current)
{
ContainerNode& root = nodeList.rootNode();
Element* next = &current;
do {
next = ElementTraversal::next(*next, &root);
} while (next && !isMatchingElement(nodeList, *next));
return next;
}
template <class NodeListType>
Element* LiveNodeListBase::previousMatchingElement(const NodeListType& nodeList, Element& current)
{
ContainerNode& root = nodeList.rootNode();
Element* previous = &current;
do {
previous = ElementTraversal::previous(*previous, &root);
} while (previous && !isMatchingElement(nodeList, *previous));
return previous;
}
template <class NodeListType>
Element* LiveNodeListBase::traverseMatchingElementsForwardToOffset(const NodeListType& nodeList, unsigned offset, Element& currentElement, unsigned& currentOffset)
{ {
ASSERT(currentOffset < offset); ASSERT(currentOffset < offset);
for (Element* next = nextMatchingElement(nodeList, currentElement); next; next = nextMatchingElement(nodeList, *next)) { for (Element* next = ElementTraversal::next(currentElement, stayWithin, isMatch); next; next = ElementTraversal::next(*next, stayWithin, isMatch)) {
if (++currentOffset == offset) if (++currentOffset == offset)
return next; return next;
} }
return 0; return 0;
} }
template <class NodeListType> template <typename MatchFunc>
Element* LiveNodeListBase::traverseMatchingElementsBackwardToOffset(const NodeListType& nodeList, unsigned offset, Element& currentElement, unsigned& currentOffset) Element* LiveNodeListBase::traverseMatchingElementsBackwardToOffset(Element& currentElement, const ContainerNode* stayWithin, unsigned offset, unsigned& currentOffset, MatchFunc isMatch)
{ {
ASSERT(currentOffset > offset); ASSERT(currentOffset > offset);
for (Element* previous = previousMatchingElement(nodeList, currentElement); previous; previous = previousMatchingElement(nodeList, *previous)) { for (Element* previous = ElementTraversal::previous(currentElement, stayWithin, isMatch); previous; previous = ElementTraversal::previous(*previous, stayWithin, isMatch)) {
if (--currentOffset == offset) if (--currentOffset == offset)
return previous; return previous;
} }
......
...@@ -255,43 +255,53 @@ static inline bool isMatchingHTMLElement(const HTMLCollection& htmlCollection, c ...@@ -255,43 +255,53 @@ static inline bool isMatchingHTMLElement(const HTMLCollection& htmlCollection, c
return false; return false;
} }
template <class NodeListType> inline bool HTMLCollection::elementMatches(const Element& element) const
inline bool isMatchingElement(const NodeListType&, const Element&);
template <> inline bool isMatchingElement(const HTMLCollection& htmlCollection, const Element& element)
{ {
// These collections apply to any kind of Elements, not just HTMLElements. // These collections apply to any kind of Elements, not just HTMLElements.
switch (htmlCollection.type()) { switch (type()) {
case DocAll: case DocAll:
case NodeChildren: case NodeChildren:
return true; return true;
case ClassCollectionType: case ClassCollectionType:
return toClassCollection(htmlCollection).elementMatches(element); return toClassCollection(*this).elementMatches(element);
case TagCollectionType: case TagCollectionType:
return toTagCollection(htmlCollection).elementMatches(element); return toTagCollection(*this).elementMatches(element);
case HTMLTagCollectionType: case HTMLTagCollectionType:
return toHTMLTagCollection(htmlCollection).elementMatches(element); return toHTMLTagCollection(*this).elementMatches(element);
case DocumentNamedItems: case DocumentNamedItems:
return toDocumentNameCollection(htmlCollection).elementMatches(element); return toDocumentNameCollection(*this).elementMatches(element);
case WindowNamedItems: case WindowNamedItems:
return toWindowNameCollection(htmlCollection).elementMatches(element); return toWindowNameCollection(*this).elementMatches(element);
default: default:
break; break;
} }
// The following only applies to HTMLElements. // The following only applies to HTMLElements.
return element.isHTMLElement() && isMatchingHTMLElement(htmlCollection, toHTMLElement(element)); return element.isHTMLElement() && isMatchingHTMLElement(*this, toHTMLElement(element));
} }
template <> inline bool isMatchingElement(const ClassCollection& collection, const Element& element) namespace {
{
return collection.elementMatches(element);
}
template <> inline bool isMatchingElement(const HTMLTagCollection& collection, const Element& element) template <class HTMLCollectionType>
{ class IsMatch {
return collection.elementMatches(element); public:
} IsMatch(const HTMLCollectionType& list)
: m_list(list)
{ }
bool operator() (const Element& element) const
{
return m_list.elementMatches(element);
}
private:
const HTMLCollectionType& m_list;
};
} // namespace
template <class HTMLCollectionType>
static inline IsMatch<HTMLCollectionType> makeIsMatch(const HTMLCollectionType& list) { return IsMatch<HTMLCollectionType>(list); }
Element* HTMLCollection::virtualItemAfter(Element*) const Element* HTMLCollection::virtualItemAfter(Element*) const
{ {
...@@ -318,53 +328,19 @@ static inline bool nameShouldBeVisibleInDocumentAll(const HTMLElement& element) ...@@ -318,53 +328,19 @@ static inline bool nameShouldBeVisibleInDocumentAll(const HTMLElement& element)
|| element.hasTagName(selectTag); || element.hasTagName(selectTag);
} }
inline Element* firstMatchingChildElement(const HTMLCollection& nodeList)
{
Element* element = ElementTraversal::firstChild(nodeList.rootNode());
while (element && !isMatchingElement(nodeList, *element))
element = ElementTraversal::nextSibling(*element);
return element;
}
inline Element* lastMatchingChildElement(const HTMLCollection& nodeList)
{
Element* element = ElementTraversal::lastChild(nodeList.rootNode());
while (element && !isMatchingElement(nodeList, *element))
element = ElementTraversal::previousSibling(*element);
return element;
}
inline Element* nextMatchingChildElement(const HTMLCollection& nodeList, Element& current)
{
Element* next = &current;
do {
next = ElementTraversal::nextSibling(*next);
} while (next && !isMatchingElement(nodeList, *next));
return next;
}
inline Element* previousMatchingChildElement(const HTMLCollection& nodeList, Element& current)
{
Element* previous = &current;
do {
previous = ElementTraversal::previousSibling(*previous);
} while (previous && !isMatchingElement(nodeList, *previous));
return previous;
}
Element* HTMLCollection::traverseToFirstElement() const Element* HTMLCollection::traverseToFirstElement() const
{ {
switch (type()) { switch (type()) {
case HTMLTagCollectionType: case HTMLTagCollectionType:
return firstMatchingElement(toHTMLTagCollection(*this)); return ElementTraversal::firstWithin(rootNode(), makeIsMatch(toHTMLTagCollection(*this)));
case ClassCollectionType: case ClassCollectionType:
return firstMatchingElement(toClassCollection(*this)); return ElementTraversal::firstWithin(rootNode(), makeIsMatch(toClassCollection(*this)));
default: default:
if (overridesItemAfter()) if (overridesItemAfter())
return virtualItemAfter(0); return virtualItemAfter(0);
if (shouldOnlyIncludeDirectChildren()) if (shouldOnlyIncludeDirectChildren())
return firstMatchingChildElement(*this); return ElementTraversal::firstChild(rootNode(), makeIsMatch(*this));
return firstMatchingElement(*this); return ElementTraversal::firstWithin(rootNode(), makeIsMatch(*this));
} }
} }
...@@ -372,8 +348,8 @@ Element* HTMLCollection::traverseToLastElement() const ...@@ -372,8 +348,8 @@ Element* HTMLCollection::traverseToLastElement() const
{ {
ASSERT(canTraverseBackward()); ASSERT(canTraverseBackward());
if (shouldOnlyIncludeDirectChildren()) if (shouldOnlyIncludeDirectChildren())
return lastMatchingChildElement(*this); return ElementTraversal::lastChild(rootNode(), makeIsMatch(*this));
return lastMatchingElement(*this); return ElementTraversal::lastWithin(rootNode(), makeIsMatch(*this));
} }
Element* HTMLCollection::traverseForwardToOffset(unsigned offset, Element& currentElement, unsigned& currentOffset) const Element* HTMLCollection::traverseForwardToOffset(unsigned offset, Element& currentElement, unsigned& currentOffset) const
...@@ -381,9 +357,9 @@ Element* HTMLCollection::traverseForwardToOffset(unsigned offset, Element& curre ...@@ -381,9 +357,9 @@ Element* HTMLCollection::traverseForwardToOffset(unsigned offset, Element& curre
ASSERT(currentOffset < offset); ASSERT(currentOffset < offset);
switch (type()) { switch (type()) {
case HTMLTagCollectionType: case HTMLTagCollectionType:
return traverseMatchingElementsForwardToOffset(toHTMLTagCollection(*this), offset, currentElement, currentOffset); return traverseMatchingElementsForwardToOffset(currentElement, &rootNode(), offset, currentOffset, makeIsMatch(toHTMLTagCollection(*this)));
case ClassCollectionType: case ClassCollectionType:
return traverseMatchingElementsForwardToOffset(toClassCollection(*this), offset, currentElement, currentOffset); return traverseMatchingElementsForwardToOffset(currentElement, &rootNode(), offset, currentOffset, makeIsMatch(toClassCollection(*this)));
default: default:
if (overridesItemAfter()) { if (overridesItemAfter()) {
for (Element* next = virtualItemAfter(&currentElement); next; next = virtualItemAfter(next)) { for (Element* next = virtualItemAfter(&currentElement); next; next = virtualItemAfter(next)) {
...@@ -393,13 +369,14 @@ Element* HTMLCollection::traverseForwardToOffset(unsigned offset, Element& curre ...@@ -393,13 +369,14 @@ Element* HTMLCollection::traverseForwardToOffset(unsigned offset, Element& curre
return 0; return 0;
} }
if (shouldOnlyIncludeDirectChildren()) { if (shouldOnlyIncludeDirectChildren()) {
for (Element* next = nextMatchingChildElement(*this, currentElement); next; next = nextMatchingChildElement(*this, *next)) { IsMatch<HTMLCollection> isMatch(*this);
for (Element* next = ElementTraversal::nextSibling(currentElement, isMatch); next; next = ElementTraversal::nextSibling(*next, isMatch)) {
if (++currentOffset == offset) if (++currentOffset == offset)
return next; return next;
} }
return 0; return 0;
} }
return traverseMatchingElementsForwardToOffset(*this, offset, currentElement, currentOffset); return traverseMatchingElementsForwardToOffset(currentElement, &rootNode(), offset, currentOffset, makeIsMatch(*this));
} }
} }
...@@ -408,13 +385,14 @@ Element* HTMLCollection::traverseBackwardToOffset(unsigned offset, Element& curr ...@@ -408,13 +385,14 @@ Element* HTMLCollection::traverseBackwardToOffset(unsigned offset, Element& curr
ASSERT(currentOffset > offset); ASSERT(currentOffset > offset);
ASSERT(canTraverseBackward()); ASSERT(canTraverseBackward());
if (shouldOnlyIncludeDirectChildren()) { if (shouldOnlyIncludeDirectChildren()) {
for (Element* previous = previousMatchingChildElement(*this, currentElement); previous; previous = previousMatchingChildElement(*this, *previous)) { IsMatch<HTMLCollection> isMatch(*this);
for (Element* previous = ElementTraversal::previousSibling(currentElement, isMatch); previous; previous = ElementTraversal::previousSibling(*previous, isMatch)) {
if (--currentOffset == offset) if (--currentOffset == offset)
return previous; return previous;
} }
return 0; return 0;
} }
return traverseMatchingElementsBackwardToOffset(*this, offset, currentElement, currentOffset); return traverseMatchingElementsBackwardToOffset(currentElement, &rootNode(), offset, currentOffset, makeIsMatch(*this));
} }
Element* HTMLCollection::namedItem(const AtomicString& name) const Element* HTMLCollection::namedItem(const AtomicString& name) const
......
...@@ -55,6 +55,7 @@ public: ...@@ -55,6 +55,7 @@ public:
void namedItems(const AtomicString& name, WillBeHeapVector<RefPtrWillBeMember<Element> >&) const; void namedItems(const AtomicString& name, WillBeHeapVector<RefPtrWillBeMember<Element> >&) const;
bool isEmpty() const { return m_collectionIndexCache.isEmpty(*this); } bool isEmpty() const { return m_collectionIndexCache.isEmpty(*this); }
bool hasExactlyOneItem() const { return m_collectionIndexCache.hasExactlyOneNode(*this); } bool hasExactlyOneItem() const { return m_collectionIndexCache.hasExactlyOneNode(*this); }
bool elementMatches(const Element&) const;
// CollectionIndexCache API. // CollectionIndexCache API.
bool canTraverseBackward() const { return !overridesItemAfter(); } bool canTraverseBackward() const { return !overridesItemAfter(); }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment