2 * Copyright (C) 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Neither the name of Google Inc. nor the names of its
11 * contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "core/dom/NodeRenderingTraversal.h"
30 #include "HTMLNames.h"
31 #include "core/dom/PseudoElement.h"
32 #include "core/dom/shadow/ComposedTreeWalker.h"
33 #include "core/rendering/RenderObject.h"
37 namespace NodeRenderingTraversal {
39 static bool isRendererReparented(const RenderObject* renderer)
41 if (!renderer->node()->isElementNode())
43 if (toElement(renderer->node())->isInTopLayer())
48 void ParentDetails::didTraverseInsertionPoint(const InsertionPoint* insertionPoint)
50 if (!m_insertionPoint) {
51 m_insertionPoint = insertionPoint;
55 ContainerNode* parent(const Node* node, ParentDetails* details)
57 // FIXME: We should probably ASSERT(!node->document().childNeedsDistributionRecalc()) here, but
58 // a bunch of things use NodeRenderingTraversal::parent in places where that looks like it could
61 if (isActiveInsertionPoint(*node))
63 ComposedTreeWalker walker(node, ComposedTreeWalker::CanStartFromShadowBoundary);
64 return toContainerNode(walker.traverseParent(walker.get(), details));
67 bool contains(const ContainerNode* container, const Node* node)
70 if (node == container)
72 node = NodeRenderingTraversal::parent(node);
77 Node* nextSibling(const Node* node)
79 ComposedTreeWalker walker(node);
80 if (node->isBeforePseudoElement()) {
86 if (walker.get() || node->isAfterPseudoElement())
89 Node* parent = walker.traverseParent(node);
90 if (parent && parent->isElementNode())
91 return toElement(parent)->pseudoElement(AFTER);
96 Node* previousSibling(const Node* node)
98 ComposedTreeWalker walker(node);
99 if (node->isAfterPseudoElement()) {
103 walker.previousSibling();
105 if (walker.get() || node->isBeforePseudoElement())
108 Node* parent = walker.traverseParent(node);
109 if (parent && parent->isElementNode())
110 return toElement(parent)->pseudoElement(BEFORE);
115 static Node* lastChild(const Node* node)
117 ComposedTreeWalker walker(node);
122 static Node* pseudoAwarePreviousSibling(const Node* node)
124 Node* previousNode = previousSibling(node);
125 Node* parentNode = parent(node);
127 if (parentNode && parentNode->isElementNode() && !previousNode) {
128 if (node->isAfterPseudoElement()) {
129 if (Node* child = lastChild(parentNode))
132 if (!node->isBeforePseudoElement())
133 return toElement(parentNode)->pseudoElement(BEFORE);
138 static Node* pseudoAwareLastChild(const Node* node)
140 if (node->isElementNode()) {
141 const Element* currentElement = toElement(node);
142 Node* last = currentElement->pseudoElement(AFTER);
146 last = lastChild(currentElement);
148 last = currentElement->pseudoElement(BEFORE);
152 return lastChild(node);
155 Node* previous(const Node* node, const Node* stayWithin)
157 if (node == stayWithin)
160 if (Node* previousNode = pseudoAwarePreviousSibling(node)) {
161 while (Node* previousLastChild = pseudoAwareLastChild(previousNode))
162 previousNode = previousLastChild;
168 static Node* firstChild(const Node* node)
170 ComposedTreeWalker walker(node);
175 static Node* pseudoAwareNextSibling(const Node* node)
177 Node* parentNode = parent(node);
178 Node* nextNode = nextSibling(node);
180 if (parentNode && parentNode->isElementNode() && !nextNode) {
181 if (node->isBeforePseudoElement()) {
182 if (Node* child = firstChild(parentNode))
185 if (!node->isAfterPseudoElement())
186 return toElement(parentNode)->pseudoElement(AFTER);
191 static Node* pseudoAwareFirstChild(const Node* node)
193 if (node->isElementNode()) {
194 const Element* currentElement = toElement(node);
195 Node* first = currentElement->pseudoElement(BEFORE);
198 first = firstChild(currentElement);
200 first = currentElement->pseudoElement(AFTER);
204 return firstChild(node);
207 Node* next(const Node* node, const Node* stayWithin)
209 if (Node* child = pseudoAwareFirstChild(node))
211 if (node == stayWithin)
213 if (Node* nextNode = pseudoAwareNextSibling(node))
215 for (Node* parentNode = parent(node); parentNode; parentNode = parent(parentNode)) {
216 if (parentNode == stayWithin)
218 if (Node* nextNode = pseudoAwareNextSibling(parentNode))
224 RenderObject* nextSiblingRenderer(const Node* node)
226 for (Node* sibling = NodeRenderingTraversal::nextSibling(node); sibling; sibling = NodeRenderingTraversal::nextSibling(sibling)) {
227 RenderObject* renderer = sibling->renderer();
228 if (renderer && !isRendererReparented(renderer))
234 RenderObject* previousSiblingRenderer(const Node* node)
236 for (Node* sibling = NodeRenderingTraversal::previousSibling(node); sibling; sibling = NodeRenderingTraversal::previousSibling(sibling)) {
237 RenderObject* renderer = sibling->renderer();
238 if (renderer && !isRendererReparented(renderer))
244 RenderObject* nextInTopLayer(const Element* element)
246 if (!element->isInTopLayer())
248 const WillBeHeapVector<RefPtrWillBeMember<Element> >& topLayerElements = element->document().topLayerElements();
249 size_t position = topLayerElements.find(element);
250 ASSERT(position != kNotFound);
251 for (size_t i = position + 1; i < topLayerElements.size(); ++i) {
252 if (RenderObject* renderer = topLayerElements[i]->renderer())