1 /* 2 * Copyright (C) 2012 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 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. 13 * 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. 25 */ 26 27 #include "config.h" 28 #include "core/dom/NodeRenderingTraversal.h" 29 30 #include "core/HTMLNames.h" 31 #include "core/dom/PseudoElement.h" 32 #include "core/dom/shadow/ComposedTreeWalker.h" 33 #include "core/rendering/RenderObject.h" 34 35 namespace WebCore { 36 37 namespace NodeRenderingTraversal { 38 39 static bool isRendererReparented(const RenderObject* renderer) 40 { 41 if (!renderer->node()->isElementNode()) 42 return false; 43 if (toElement(renderer->node())->isInTopLayer()) 44 return true; 45 return false; 46 } 47 48 void ParentDetails::didTraverseInsertionPoint(const InsertionPoint* insertionPoint) 49 { 50 if (!m_insertionPoint) { 51 m_insertionPoint = insertionPoint; 52 } 53 } 54 55 ContainerNode* parent(const Node* node, ParentDetails* details) 56 { 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 59 // be false. 60 ASSERT(node); 61 if (isActiveInsertionPoint(*node)) 62 return 0; 63 ComposedTreeWalker walker(node, ComposedTreeWalker::CanStartFromShadowBoundary); 64 return toContainerNode(walker.traverseParent(walker.get(), details)); 65 } 66 67 bool contains(const ContainerNode* container, const Node* node) 68 { 69 while (node) { 70 if (node == container) 71 return true; 72 node = NodeRenderingTraversal::parent(node); 73 } 74 return false; 75 } 76 77 Node* nextSibling(const Node* node) 78 { 79 ComposedTreeWalker walker(node); 80 if (node->isBeforePseudoElement()) { 81 walker.parent(); 82 walker.firstChild(); 83 } else 84 walker.nextSibling(); 85 86 if (walker.get() || node->isAfterPseudoElement()) 87 return walker.get(); 88 89 Node* parent = walker.traverseParent(node); 90 if (parent && parent->isElementNode()) 91 return toElement(parent)->pseudoElement(AFTER); 92 93 return 0; 94 } 95 96 Node* previousSibling(const Node* node) 97 { 98 ComposedTreeWalker walker(node); 99 if (node->isAfterPseudoElement()) { 100 walker.parent(); 101 walker.lastChild(); 102 } else 103 walker.previousSibling(); 104 105 if (walker.get() || node->isBeforePseudoElement()) 106 return walker.get(); 107 108 Node* parent = walker.traverseParent(node); 109 if (parent && parent->isElementNode()) 110 return toElement(parent)->pseudoElement(BEFORE); 111 112 return 0; 113 } 114 115 static Node* lastChild(const Node* node) 116 { 117 ComposedTreeWalker walker(node); 118 walker.lastChild(); 119 return walker.get(); 120 } 121 122 static Node* pseudoAwarePreviousSibling(const Node* node) 123 { 124 Node* previousNode = previousSibling(node); 125 Node* parentNode = parent(node); 126 127 if (parentNode && parentNode->isElementNode() && !previousNode) { 128 if (node->isAfterPseudoElement()) { 129 if (Node* child = lastChild(parentNode)) 130 return child; 131 } 132 if (!node->isBeforePseudoElement()) 133 return toElement(parentNode)->pseudoElement(BEFORE); 134 } 135 return previousNode; 136 } 137 138 static Node* pseudoAwareLastChild(const Node* node) 139 { 140 if (node->isElementNode()) { 141 const Element* currentElement = toElement(node); 142 Node* last = currentElement->pseudoElement(AFTER); 143 if (last) 144 return last; 145 146 last = lastChild(currentElement); 147 if (!last) 148 last = currentElement->pseudoElement(BEFORE); 149 return last; 150 } 151 152 return lastChild(node); 153 } 154 155 Node* previous(const Node* node, const Node* stayWithin) 156 { 157 if (node == stayWithin) 158 return 0; 159 160 if (Node* previousNode = pseudoAwarePreviousSibling(node)) { 161 while (Node* previousLastChild = pseudoAwareLastChild(previousNode)) 162 previousNode = previousLastChild; 163 return previousNode; 164 } 165 return parent(node); 166 } 167 168 static Node* firstChild(const Node* node) 169 { 170 ComposedTreeWalker walker(node); 171 walker.firstChild(); 172 return walker.get(); 173 } 174 175 static Node* pseudoAwareNextSibling(const Node* node) 176 { 177 Node* parentNode = parent(node); 178 Node* nextNode = nextSibling(node); 179 180 if (parentNode && parentNode->isElementNode() && !nextNode) { 181 if (node->isBeforePseudoElement()) { 182 if (Node* child = firstChild(parentNode)) 183 return child; 184 } 185 if (!node->isAfterPseudoElement()) 186 return toElement(parentNode)->pseudoElement(AFTER); 187 } 188 return nextNode; 189 } 190 191 static Node* pseudoAwareFirstChild(const Node* node) 192 { 193 if (node->isElementNode()) { 194 const Element* currentElement = toElement(node); 195 Node* first = currentElement->pseudoElement(BEFORE); 196 if (first) 197 return first; 198 first = firstChild(currentElement); 199 if (!first) 200 first = currentElement->pseudoElement(AFTER); 201 return first; 202 } 203 204 return firstChild(node); 205 } 206 207 Node* next(const Node* node, const Node* stayWithin) 208 { 209 if (Node* child = pseudoAwareFirstChild(node)) 210 return child; 211 if (node == stayWithin) 212 return 0; 213 if (Node* nextNode = pseudoAwareNextSibling(node)) 214 return nextNode; 215 for (Node* parentNode = parent(node); parentNode; parentNode = parent(parentNode)) { 216 if (parentNode == stayWithin) 217 return 0; 218 if (Node* nextNode = pseudoAwareNextSibling(parentNode)) 219 return nextNode; 220 } 221 return 0; 222 } 223 224 RenderObject* nextSiblingRenderer(const Node* node) 225 { 226 for (Node* sibling = NodeRenderingTraversal::nextSibling(node); sibling; sibling = NodeRenderingTraversal::nextSibling(sibling)) { 227 RenderObject* renderer = sibling->renderer(); 228 if (renderer && !isRendererReparented(renderer)) 229 return renderer; 230 } 231 return 0; 232 } 233 234 RenderObject* previousSiblingRenderer(const Node* node) 235 { 236 for (Node* sibling = NodeRenderingTraversal::previousSibling(node); sibling; sibling = NodeRenderingTraversal::previousSibling(sibling)) { 237 RenderObject* renderer = sibling->renderer(); 238 if (renderer && !isRendererReparented(renderer)) 239 return renderer; 240 } 241 return 0; 242 } 243 244 RenderObject* nextInTopLayer(const Element* element) 245 { 246 if (!element->isInTopLayer()) 247 return 0; 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()) 253 return renderer; 254 } 255 return 0; 256 } 257 258 } 259 260 } // namespace 261