/* * Copyright (C) 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef CollectionTraversal_h #define CollectionTraversal_h #include "CollectionType.h" #include "ElementChildIterator.h" #include "ElementDescendantIterator.h" namespace WebCore { template struct CollectionTraversal { }; template <> struct CollectionTraversal { using Iterator = ElementDescendantIterator; static ElementDescendantIterator end(ContainerNode&) { return ElementDescendantIterator(); } template static ElementDescendantIterator begin(const CollectionClass&, ContainerNode& rootNode); template static ElementDescendantIterator last(const CollectionClass&, ContainerNode& rootNode); template static void traverseForward(const CollectionClass&, ElementDescendantIterator& current, unsigned count, unsigned& traversedCount); template static void traverseBackward(const CollectionClass&, ElementDescendantIterator& current, unsigned count); }; template inline ElementDescendantIterator CollectionTraversal::begin(const CollectionClass& collection, ContainerNode& rootNode) { auto descendants = elementDescendants(rootNode); auto end = descendants.end(); for (auto it = descendants.begin(); it != end; ++it) { if (collection.elementMatches(*it)) { // Drop iterator assertions because HTMLCollections / NodeList use a fine-grained invalidation scheme. it.dropAssertions(); return it; } } return end; } template inline ElementDescendantIterator CollectionTraversal::last(const CollectionClass& collection, ContainerNode& rootNode) { auto descendants = elementDescendants(rootNode); ElementDescendantIterator invalid; for (auto it = descendants.last(); it != invalid; --it) { if (collection.elementMatches(*it)) { // Drop iterator assertions because HTMLCollections / NodeList use a fine-grained invalidation scheme. it.dropAssertions(); return it; } } return invalid; } template inline void CollectionTraversal::traverseForward(const CollectionClass& collection, ElementDescendantIterator& current, unsigned count, unsigned& traversedCount) { ASSERT(collection.elementMatches(*current)); ElementDescendantIterator invalid; for (traversedCount = 0; traversedCount < count; ++traversedCount) { do { ++current; if (current == invalid) return; } while (!collection.elementMatches(*current)); } } template inline void CollectionTraversal::traverseBackward(const CollectionClass& collection, ElementDescendantIterator& current, unsigned count) { ASSERT(collection.elementMatches(*current)); ElementDescendantIterator invalid; for (; count; --count) { do { --current; if (current == invalid) return; } while (!collection.elementMatches(*current)); } } template <> struct CollectionTraversal { using Iterator = ElementChildIterator; static ElementChildIterator end(ContainerNode& rootNode) { return ElementChildIterator(rootNode); } template static ElementChildIterator begin(const CollectionClass&, ContainerNode& rootNode); template static ElementChildIterator last(const CollectionClass&, ContainerNode& rootNode); template static void traverseForward(const CollectionClass&, ElementChildIterator& current, unsigned count, unsigned& traversedCount); template static void traverseBackward(const CollectionClass&, ElementChildIterator& current, unsigned count); }; template inline ElementChildIterator CollectionTraversal::begin(const CollectionClass& collection, ContainerNode& rootNode) { auto children = childrenOfType(rootNode); auto end = children.end(); for (auto it = children.begin(); it != end; ++it) { if (collection.elementMatches(*it)) { // Drop iterator assertions because HTMLCollections / NodeList use a fine-grained invalidation scheme. it.dropAssertions(); return it; } } return end; } template inline ElementChildIterator CollectionTraversal::last(const CollectionClass& collection, ContainerNode& rootNode) { auto children = childrenOfType(rootNode); ElementChildIterator invalid(collection.rootNode()); ElementChildIterator last(rootNode, children.last()); for (auto it = last; it != invalid; --it) { if (collection.elementMatches(*it)) { // Drop iterator assertions because HTMLCollections / NodeList use a fine-grained invalidation scheme. it.dropAssertions(); return it; } } return invalid; } template inline void CollectionTraversal::traverseForward(const CollectionClass& collection, ElementChildIterator& current, unsigned count, unsigned& traversedCount) { ASSERT(collection.elementMatches(*current)); ElementChildIterator invalid(collection.rootNode()); for (traversedCount = 0; traversedCount < count; ++traversedCount) { do { ++current; if (current == invalid) return; } while (!collection.elementMatches(*current)); } } template inline void CollectionTraversal::traverseBackward(const CollectionClass& collection, ElementChildIterator& current, unsigned count) { ASSERT(collection.elementMatches(*current)); ElementChildIterator invalid(collection.rootNode()); for (; count; --count) { do { --current; if (current == invalid) return; } while (!collection.elementMatches(*current)); } } template <> struct CollectionTraversal { using Iterator = Element*; static Element* end(ContainerNode&) { return nullptr; } template static Element* begin(const CollectionClass&, ContainerNode&); template static Element* last(const CollectionClass&, ContainerNode&); template static void traverseForward(const CollectionClass&, Element*& current, unsigned count, unsigned& traversedCount); template static void traverseBackward(const CollectionClass&, Element*&, unsigned count); }; template inline Element* CollectionTraversal::begin(const CollectionClass& collection, ContainerNode&) { return collection.customElementAfter(nullptr); } template inline Element* CollectionTraversal::last(const CollectionClass&, ContainerNode&) { ASSERT_NOT_REACHED(); return nullptr; } template inline void CollectionTraversal::traverseForward(const CollectionClass& collection, Element*& current, unsigned count, unsigned& traversedCount) { Element* element = current; for (traversedCount = 0; traversedCount < count; ++traversedCount) { element = collection.customElementAfter(element); if (!element) { current = nullptr; return; } } current = element; } template inline void CollectionTraversal::traverseBackward(const CollectionClass&, Element*&, unsigned count) { UNUSED_PARAM(count); ASSERT_NOT_REACHED(); } } // namespace WebCore #endif // CollectionTraversal_h