blob: 1754eba2cb269b0605906e4dd60c277549b31c37 [file] [log] [blame]
/*
* 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>(&current);
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, &current);
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, &current, 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, &current);
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, &current, is_match);
return element;
}
template <class ElementType>
inline ElementType* Traversal<ElementType>::LastWithinOrSelf(
ElementType& current) {
if (ElementType* last_descendant = LastWithin(current))
return last_descendant;
return &current;
}
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