| /* |
| * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| * (C) 1999 Antti Koivisto (koivisto@kde.org) |
| * (C) 2001 Dirk Mueller (mueller@kde.org) |
| * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 |
| * Apple Inc. All rights reserved. |
| * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. |
| * (http://www.torchmobile.com/) |
| * Copyright (C) 2014 Samsung Electronics. All rights reserved. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public License |
| * along with this library; see the file COPYING.LIB. If not, write to |
| * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| * |
| */ |
| |
| #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_DOM_ELEMENT_TRAVERSAL_H_ |
| #define THIRD_PARTY_BLINK_RENDERER_CORE_DOM_ELEMENT_TRAVERSAL_H_ |
| |
| #include "third_party/blink/renderer/core/dom/element.h" |
| #include "third_party/blink/renderer/core/dom/node_traversal.h" |
| #include "third_party/blink/renderer/core/dom/traversal_range.h" |
| #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" |
| |
| namespace blink { |
| |
| class HasTagName { |
| STACK_ALLOCATED(); |
| |
| public: |
| explicit HasTagName(const QualifiedName& tag_name) : tag_name_(tag_name) {} |
| bool operator()(const Element& element) const { |
| return element.HasTagName(tag_name_); |
| } |
| |
| private: |
| const QualifiedName tag_name_; |
| }; |
| |
| // This class is used to traverse the DOM tree. It isn't meant to be |
| // constructed; instead, callers invoke the static methods, after templating it |
| // so that ElementType is the type of element they are interested in traversing. |
| // Traversals can also be predicated on a matcher, which will be used to |
| // filter the returned elements. A matcher is a callable - an object of a class |
| // that defines operator(). HasTagName above is an example of a matcher. |
| // |
| // For example, a caller could do this: |
| // Traversal<Element>::firstChild(some_node, |
| // HasTagName(html_names::kTitleTag)); |
| // |
| // This invocation would return the first child of |some_node| (which has to be |
| // a ContainerNode) for which HasTagName(html_names::kTitleTag) returned true, |
| // so it would return the first child of |someNode| which is a <title> element. |
| // If the caller needs to traverse a Node this way, it's necessary to first |
| // check Node::IsContainerNode() and then use To<ContainerNode>(). Another way |
| // to achieve same behaviour is to use DynamicTo<ContainerNode>() which |
| // checks Node::IsContainerNode() and then returns container |
| // node. If the conditional check fails then it returns nullptr. |
| // DynamicTo<ContainerNode>() wraps IsContainerNode() so there is no need of |
| // an explicit conditional check. |
| // |
| // When looking for a specific element type, it is more efficient to do this: |
| // Traversal<HTMLTitleElement>::firstChild(someNode); |
| // |
| // Traversal can also be used to find ancestors and descendants; see the |
| // documentation in the class body below. |
| // |
| // Note that these functions do not traverse into child shadow trees of any |
| // shadow hosts they encounter. If you need to traverse the shadow DOM, you can |
| // manually traverse the shadow trees using a second Traversal, or use |
| // FlatTreeTraversal. |
| // |
| // ElementTraversal is a specialized version of Traversal<Element>. |
| template <class ElementType> |
| class Traversal { |
| STATIC_ONLY(Traversal); |
| |
| public: |
| using TraversalNodeType = ElementType; |
| // First or last ElementType child of the node. |
| static ElementType* FirstChild(const ContainerNode& 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 Node& current) { |
| return LastChildTemplate(current); |
| } |
| template <class MatchFunc> |
| static ElementType* LastChild(const ContainerNode&, MatchFunc); |
| |
| // First ElementType ancestor of the node. |
| static ElementType* FirstAncestor(const Node& current); |
| static ElementType* FirstAncestorOrSelf(Node& current) { |
| return FirstAncestorOrSelfTemplate(current); |
| } |
| static ElementType* FirstAncestorOrSelf(Element& current) { |
| return FirstAncestorOrSelfTemplate(current); |
| } |
| static const ElementType* FirstAncestorOrSelf(const Node& current) { |
| return FirstAncestorOrSelfTemplate(const_cast<Node&>(current)); |
| } |
| static const ElementType* FirstAncestorOrSelf(const Element& current) { |
| return FirstAncestorOrSelfTemplate(const_cast<Element&>(current)); |
| } |
| |
| // First or last ElementType descendant of the node. |
| // For pure Elements firstWithin() is always the same as firstChild(). |
| static ElementType* FirstWithin(const ContainerNode& current) { |
| return FirstWithinTemplate(current); |
| } |
| static ElementType* FirstWithin(const Node& current) { |
| return FirstWithinTemplate(current); |
| } |
| template <typename MatchFunc> |
| static ElementType* FirstWithin(const ContainerNode&, MatchFunc); |
| |
| static ElementType* InclusiveFirstWithin(Node& current) { |
| if (IsElementOfType<const ElementType>(current)) |
| return To<ElementType>(¤t); |
| return FirstWithin(current); |
| } |
| |
| static ElementType* LastWithin(const ContainerNode& current) { |
| return LastWithinTemplate(current); |
| } |
| static ElementType* LastWithin(const Node& current) { |
| return LastWithinTemplate(current); |
| } |
| template <class MatchFunc> |
| static ElementType* LastWithin(const ContainerNode&, MatchFunc); |
| static ElementType* LastWithinOrSelf(ElementType&); |
| |
| // Pre-order traversal skipping non-element nodes. |
| static ElementType* Next(const ContainerNode& current) { |
| return NextTemplate(current); |
| } |
| static ElementType* Next(const Node& current) { |
| return NextTemplate(current); |
| } |
| static ElementType* Next(const ContainerNode& current, |
| const Node* stay_within) { |
| return NextTemplate(current, stay_within); |
| } |
| static ElementType* Next(const Node& current, const Node* stay_within) { |
| return NextTemplate(current, stay_within); |
| } |
| template <class MatchFunc> |
| static ElementType* Next(const ContainerNode& current, |
| const Node* stay_within, |
| MatchFunc); |
| static ElementType* Previous(const Node&); |
| static ElementType* Previous(const Node&, const Node* stay_within); |
| template <class MatchFunc> |
| static ElementType* Previous(const ContainerNode& current, |
| const Node* stay_within, |
| MatchFunc); |
| |
| // Like next, but skips children. |
| static ElementType* NextSkippingChildren(const Node&); |
| static ElementType* NextSkippingChildren(const Node&, |
| const Node* stay_within); |
| |
| // Pre-order traversal including the pseudo-elements. |
| static ElementType* PreviousIncludingPseudo( |
| const Node&, |
| const Node* stay_within = nullptr); |
| static ElementType* NextIncludingPseudo(const Node&, |
| const Node* stay_within = nullptr); |
| static ElementType* NextIncludingPseudoSkippingChildren( |
| const Node&, |
| const Node* stay_within = nullptr); |
| |
| // Utility function to traverse only the element and pseudo-element siblings |
| // of a node. |
| static ElementType* PseudoAwarePreviousSibling(const Node&); |
| |
| // Previous / Next sibling. |
| static ElementType* PreviousSibling(const Node&); |
| template <class MatchFunc> |
| static ElementType* PreviousSibling(const Node&, MatchFunc); |
| static ElementType* NextSibling(const Node&); |
| template <class MatchFunc> |
| static ElementType* NextSibling(const Node&, MatchFunc); |
| |
| static TraversalSiblingRange<Traversal<ElementType>> ChildrenOf(const Node&); |
| static TraversalDescendantRange<Traversal<ElementType>> DescendantsOf( |
| const Node&); |
| static TraversalInclusiveDescendantRange<Traversal<ElementType>> |
| InclusiveDescendantsOf(const ElementType&); |
| static TraversalNextRange<Traversal<ElementType>> StartsAt( |
| const ElementType&); |
| static TraversalNextRange<Traversal<ElementType>> StartsAfter(const Node&); |
| |
| private: |
| template <class NodeType> |
| static ElementType* FirstChildTemplate(NodeType&); |
| template <class NodeType> |
| static ElementType* LastChildTemplate(NodeType&); |
| template <class NodeType> |
| static ElementType* FirstAncestorOrSelfTemplate(NodeType&); |
| template <class NodeType> |
| static ElementType* FirstWithinTemplate(NodeType&); |
| template <class NodeType> |
| static ElementType* LastWithinTemplate(NodeType&); |
| template <class NodeType> |
| static ElementType* NextTemplate(NodeType&); |
| template <class NodeType> |
| static ElementType* NextTemplate(NodeType&, const Node* stay_within); |
| }; |
| |
| typedef Traversal<Element> ElementTraversal; |
| |
| template <class ElementType> |
| inline TraversalSiblingRange<Traversal<ElementType>> |
| Traversal<ElementType>::ChildrenOf(const Node& start) { |
| return TraversalSiblingRange<Traversal<ElementType>>( |
| Traversal<ElementType>::FirstChild(start)); |
| } |
| |
| template <class ElementType> |
| inline TraversalDescendantRange<Traversal<ElementType>> |
| Traversal<ElementType>::DescendantsOf(const Node& root) { |
| return TraversalDescendantRange<Traversal<ElementType>>(&root); |
| } |
| |
| template <class ElementType> |
| inline TraversalInclusiveDescendantRange<Traversal<ElementType>> |
| Traversal<ElementType>::InclusiveDescendantsOf(const ElementType& root) { |
| return TraversalInclusiveDescendantRange<Traversal<ElementType>>(&root); |
| } |
| |
| template <class ElementType> |
| inline TraversalNextRange<Traversal<ElementType>> |
| Traversal<ElementType>::StartsAt(const ElementType& start) { |
| return TraversalNextRange<Traversal<ElementType>>(&start); |
| } |
| |
| template <class ElementType> |
| inline TraversalNextRange<Traversal<ElementType>> |
| Traversal<ElementType>::StartsAfter(const Node& start) { |
| return TraversalNextRange<Traversal<ElementType>>( |
| Traversal<ElementType>::Next(start)); |
| } |
| |
| // Specialized for pure Element to exploit the fact that Elements parent is |
| // always either another Element or the root. |
| template <> |
| template <class NodeType> |
| inline Element* Traversal<Element>::FirstWithinTemplate(NodeType& current) { |
| return FirstChildTemplate(current); |
| } |
| |
| template <> |
| template <class NodeType> |
| inline Element* Traversal<Element>::NextTemplate(NodeType& current) { |
| Node* node = NodeTraversal::Next(current); |
| while (node && !node->IsElementNode()) |
| node = NodeTraversal::NextSkippingChildren(*node); |
| return To<Element>(node); |
| } |
| |
| template <> |
| template <class NodeType> |
| inline Element* Traversal<Element>::NextTemplate(NodeType& current, |
| const Node* stay_within) { |
| Node* node = NodeTraversal::Next(current, stay_within); |
| while (node && !node->IsElementNode()) |
| node = NodeTraversal::NextSkippingChildren(*node, stay_within); |
| return To<Element>(node); |
| } |
| |
| // Generic versions. |
| template <class ElementType> |
| template <class NodeType> |
| inline ElementType* Traversal<ElementType>::FirstChildTemplate( |
| NodeType& current) { |
| Node* node = current.firstChild(); |
| while (node && !IsElementOfType<const ElementType>(*node)) |
| node = node->nextSibling(); |
| return To<ElementType>(node); |
| } |
| |
| template <class ElementType> |
| template <class MatchFunc> |
| inline ElementType* Traversal<ElementType>::FirstChild( |
| const ContainerNode& current, |
| MatchFunc is_match) { |
| ElementType* element = Traversal<ElementType>::FirstChild(current); |
| while (element && !is_match(*element)) |
| element = Traversal<ElementType>::NextSibling(*element); |
| return element; |
| } |
| |
| template <class ElementType> |
| inline ElementType* Traversal<ElementType>::FirstAncestor(const Node& current) { |
| ContainerNode* ancestor = current.parentNode(); |
| while (ancestor && !IsElementOfType<const ElementType>(*ancestor)) |
| ancestor = ancestor->parentNode(); |
| return To<ElementType>(ancestor); |
| } |
| |
| template <class ElementType> |
| template <class NodeType> |
| inline ElementType* Traversal<ElementType>::FirstAncestorOrSelfTemplate( |
| NodeType& current) { |
| if (IsElementOfType<const ElementType>(current)) |
| return &To<ElementType>(current); |
| return FirstAncestor(current); |
| } |
| |
| template <class ElementType> |
| template <class NodeType> |
| inline ElementType* Traversal<ElementType>::LastChildTemplate( |
| NodeType& current) { |
| Node* node = current.lastChild(); |
| while (node && !IsElementOfType<const ElementType>(*node)) |
| node = node->previousSibling(); |
| return To<ElementType>(node); |
| } |
| |
| template <class ElementType> |
| template <class MatchFunc> |
| inline ElementType* Traversal<ElementType>::LastChild( |
| const ContainerNode& current, |
| MatchFunc is_match) { |
| ElementType* element = Traversal<ElementType>::LastChild(current); |
| while (element && !is_match(*element)) |
| element = Traversal<ElementType>::PreviousSibling(*element); |
| return element; |
| } |
| |
| template <class ElementType> |
| template <class NodeType> |
| inline ElementType* Traversal<ElementType>::FirstWithinTemplate( |
| NodeType& current) { |
| Node* node = current.firstChild(); |
| while (node && !IsElementOfType<const ElementType>(*node)) |
| node = NodeTraversal::Next(*node, ¤t); |
| return To<ElementType>(node); |
| } |
| |
| template <class ElementType> |
| template <typename MatchFunc> |
| inline ElementType* Traversal<ElementType>::FirstWithin( |
| const ContainerNode& current, |
| MatchFunc is_match) { |
| ElementType* element = Traversal<ElementType>::FirstWithin(current); |
| while (element && !is_match(*element)) |
| element = Traversal<ElementType>::Next(*element, ¤t, is_match); |
| return element; |
| } |
| |
| template <class ElementType> |
| template <class NodeType> |
| inline ElementType* Traversal<ElementType>::LastWithinTemplate( |
| NodeType& current) { |
| Node* node = NodeTraversal::LastWithin(current); |
| while (node && !IsElementOfType<const ElementType>(*node)) |
| node = NodeTraversal::Previous(*node, ¤t); |
| return To<ElementType>(node); |
| } |
| |
| template <class ElementType> |
| template <class MatchFunc> |
| inline ElementType* Traversal<ElementType>::LastWithin( |
| const ContainerNode& current, |
| MatchFunc is_match) { |
| ElementType* element = Traversal<ElementType>::LastWithin(current); |
| while (element && !is_match(*element)) |
| element = Traversal<ElementType>::Previous(*element, ¤t, is_match); |
| return element; |
| } |
| |
| template <class ElementType> |
| inline ElementType* Traversal<ElementType>::LastWithinOrSelf( |
| ElementType& current) { |
| if (ElementType* last_descendant = LastWithin(current)) |
| return last_descendant; |
| return ¤t; |
| } |
| |
| template <class ElementType> |
| template <class NodeType> |
| inline ElementType* Traversal<ElementType>::NextTemplate(NodeType& current) { |
| Node* node = NodeTraversal::Next(current); |
| while (node && !IsElementOfType<const ElementType>(*node)) |
| node = NodeTraversal::Next(*node); |
| return To<ElementType>(node); |
| } |
| |
| template <class ElementType> |
| template <class NodeType> |
| inline ElementType* Traversal<ElementType>::NextTemplate( |
| NodeType& current, |
| const Node* stay_within) { |
| Node* node = NodeTraversal::Next(current, stay_within); |
| while (node && !IsElementOfType<const ElementType>(*node)) |
| node = NodeTraversal::Next(*node, stay_within); |
| return To<ElementType>(node); |
| } |
| |
| template <class ElementType> |
| template <class MatchFunc> |
| inline ElementType* Traversal<ElementType>::Next(const ContainerNode& current, |
| const Node* stay_within, |
| MatchFunc is_match) { |
| ElementType* element = Traversal<ElementType>::Next(current, stay_within); |
| while (element && !is_match(*element)) |
| element = Traversal<ElementType>::Next(*element, stay_within); |
| return element; |
| } |
| |
| template <class ElementType> |
| inline ElementType* Traversal<ElementType>::Previous(const Node& current) { |
| Node* node = NodeTraversal::Previous(current); |
| while (node && !IsElementOfType<const ElementType>(*node)) |
| node = NodeTraversal::Previous(*node); |
| return To<ElementType>(node); |
| } |
| |
| template <class ElementType> |
| inline ElementType* Traversal<ElementType>::Previous(const Node& current, |
| const Node* stay_within) { |
| Node* node = NodeTraversal::Previous(current, stay_within); |
| while (node && !IsElementOfType<const ElementType>(*node)) |
| node = NodeTraversal::Previous(*node, stay_within); |
| return To<ElementType>(node); |
| } |
| |
| template <class ElementType> |
| template <class MatchFunc> |
| inline ElementType* Traversal<ElementType>::Previous( |
| const ContainerNode& current, |
| const Node* stay_within, |
| MatchFunc is_match) { |
| ElementType* element = Traversal<ElementType>::Previous(current, stay_within); |
| while (element && !is_match(*element)) |
| element = Traversal<ElementType>::Previous(*element, stay_within); |
| return element; |
| } |
| |
| template <class ElementType> |
| inline ElementType* Traversal<ElementType>::NextSkippingChildren( |
| const Node& current) { |
| Node* node = NodeTraversal::NextSkippingChildren(current); |
| while (node && !IsElementOfType<const ElementType>(*node)) |
| node = NodeTraversal::NextSkippingChildren(*node); |
| return To<ElementType>(node); |
| } |
| |
| template <class ElementType> |
| inline ElementType* Traversal<ElementType>::NextSkippingChildren( |
| const Node& current, |
| const Node* stay_within) { |
| Node* node = NodeTraversal::NextSkippingChildren(current, stay_within); |
| while (node && !IsElementOfType<const ElementType>(*node)) |
| node = NodeTraversal::NextSkippingChildren(*node, stay_within); |
| return To<ElementType>(node); |
| } |
| |
| template <class ElementType> |
| inline ElementType* Traversal<ElementType>::PreviousIncludingPseudo( |
| const Node& current, |
| const Node* stay_within) { |
| Node* node = NodeTraversal::PreviousIncludingPseudo(current, stay_within); |
| while (node && !IsElementOfType<const ElementType>(*node)) |
| node = NodeTraversal::PreviousIncludingPseudo(*node, stay_within); |
| return To<ElementType>(node); |
| } |
| |
| template <class ElementType> |
| inline ElementType* Traversal<ElementType>::NextIncludingPseudo( |
| const Node& current, |
| const Node* stay_within) { |
| Node* node = NodeTraversal::NextIncludingPseudo(current, stay_within); |
| while (node && !IsElementOfType<const ElementType>(*node)) |
| node = NodeTraversal::NextIncludingPseudo(*node, stay_within); |
| return To<ElementType>(node); |
| } |
| |
| template <class ElementType> |
| inline ElementType* Traversal<ElementType>::NextIncludingPseudoSkippingChildren( |
| const Node& current, |
| const Node* stay_within) { |
| Node* node = |
| NodeTraversal::NextIncludingPseudoSkippingChildren(current, stay_within); |
| while (node && !IsElementOfType<const ElementType>(*node)) |
| node = |
| NodeTraversal::NextIncludingPseudoSkippingChildren(*node, stay_within); |
| return To<ElementType>(node); |
| } |
| |
| template <class ElementType> |
| inline ElementType* Traversal<ElementType>::PseudoAwarePreviousSibling( |
| const Node& current) { |
| Node* node = current.PseudoAwarePreviousSibling(); |
| while (node && !IsElementOfType<const ElementType>(*node)) |
| node = node->PseudoAwarePreviousSibling(); |
| return To<ElementType>(node); |
| } |
| |
| template <class ElementType> |
| inline ElementType* Traversal<ElementType>::PreviousSibling( |
| const Node& current) { |
| Node* node = current.previousSibling(); |
| while (node && !IsElementOfType<const ElementType>(*node)) |
| node = node->previousSibling(); |
| return To<ElementType>(node); |
| } |
| |
| template <class ElementType> |
| template <class MatchFunc> |
| inline ElementType* Traversal<ElementType>::PreviousSibling( |
| const Node& current, |
| MatchFunc is_match) { |
| ElementType* element = Traversal<ElementType>::PreviousSibling(current); |
| while (element && !is_match(*element)) |
| element = Traversal<ElementType>::PreviousSibling(*element); |
| return element; |
| } |
| |
| template <class ElementType> |
| inline ElementType* Traversal<ElementType>::NextSibling(const Node& current) { |
| Node* node = current.nextSibling(); |
| while (node && !IsElementOfType<const ElementType>(*node)) |
| node = node->nextSibling(); |
| return To<ElementType>(node); |
| } |
| |
| template <class ElementType> |
| template <class MatchFunc> |
| inline ElementType* Traversal<ElementType>::NextSibling(const Node& current, |
| MatchFunc is_match) { |
| ElementType* element = Traversal<ElementType>::NextSibling(current); |
| while (element && !is_match(*element)) |
| element = Traversal<ElementType>::NextSibling(*element); |
| return element; |
| } |
| |
| } // namespace blink |
| |
| #endif |