| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2012 Google Inc. All rights reserved. | 2 * Copyright (C) 2012 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Neither the name of Google Inc. nor the names of its | 10 * * Neither the name of Google Inc. nor the names of its |
| 11 * contributors may be used to endorse or promote products derived from | 11 * contributors may be used to endorse or promote products derived from |
| 12 * this software without specific prior written permission. | 12 * this software without specific prior written permission. |
| 13 * | 13 * |
| 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 25 */ | 25 */ |
| 26 | 26 |
| 27 #include "core/dom/shadow/ComposedTreeTraversal.h" | 27 #include "core/dom/shadow/FlatTreeTraversal.h" |
| 28 | 28 |
| 29 #include "core/dom/Element.h" | 29 #include "core/dom/Element.h" |
| 30 #include "core/dom/shadow/ElementShadow.h" | 30 #include "core/dom/shadow/ElementShadow.h" |
| 31 #include "core/html/HTMLShadowElement.h" | 31 #include "core/html/HTMLShadowElement.h" |
| 32 #include "core/html/HTMLSlotElement.h" | 32 #include "core/html/HTMLSlotElement.h" |
| 33 | 33 |
| 34 namespace blink { | 34 namespace blink { |
| 35 | 35 |
| 36 static inline ElementShadow* shadowFor(const Node& node) | 36 static inline ElementShadow* shadowFor(const Node& node) |
| 37 { | 37 { |
| 38 return node.isElementNode() ? toElement(node).shadow() : nullptr; | 38 return node.isElementNode() ? toElement(node).shadow() : nullptr; |
| 39 } | 39 } |
| 40 | 40 |
| 41 static inline bool canBeDistributedToInsertionPoint(const Node& node) | 41 static inline bool canBeDistributedToInsertionPoint(const Node& node) |
| 42 { | 42 { |
| 43 return node.isInV0ShadowTree() || node.isChildOfV0ShadowHost(); | 43 return node.isInV0ShadowTree() || node.isChildOfV0ShadowHost(); |
| 44 } | 44 } |
| 45 | 45 |
| 46 Node* ComposedTreeTraversal::traverseChild(const Node& node, TraversalDirection
direction) | 46 Node* FlatTreeTraversal::traverseChild(const Node& node, TraversalDirection dire
ction) |
| 47 { | 47 { |
| 48 ElementShadow* shadow = shadowFor(node); | 48 ElementShadow* shadow = shadowFor(node); |
| 49 if (shadow) { | 49 if (shadow) { |
| 50 ShadowRoot& shadowRoot = shadow->youngestShadowRoot(); | 50 ShadowRoot& shadowRoot = shadow->youngestShadowRoot(); |
| 51 return resolveDistributionStartingAt(direction == TraversalDirectionForw
ard ? shadowRoot.firstChild() : shadowRoot.lastChild(), direction); | 51 return resolveDistributionStartingAt(direction == TraversalDirectionForw
ard ? shadowRoot.firstChild() : shadowRoot.lastChild(), direction); |
| 52 } | 52 } |
| 53 return resolveDistributionStartingAt(direction == TraversalDirectionForward
? node.firstChild() : node.lastChild(), direction); | 53 return resolveDistributionStartingAt(direction == TraversalDirectionForward
? node.firstChild() : node.lastChild(), direction); |
| 54 } | 54 } |
| 55 | 55 |
| 56 Node* ComposedTreeTraversal::resolveDistributionStartingAt(const Node* node, Tra
versalDirection direction) | 56 Node* FlatTreeTraversal::resolveDistributionStartingAt(const Node* node, Travers
alDirection direction) |
| 57 { | 57 { |
| 58 if (!node) | 58 if (!node) |
| 59 return nullptr; | 59 return nullptr; |
| 60 for (const Node* sibling = node; sibling; sibling = (direction == TraversalD
irectionForward ? sibling->nextSibling() : sibling->previousSibling())) { | 60 for (const Node* sibling = node; sibling; sibling = (direction == TraversalD
irectionForward ? sibling->nextSibling() : sibling->previousSibling())) { |
| 61 if (isHTMLSlotElement(*sibling)) { | 61 if (isHTMLSlotElement(*sibling)) { |
| 62 const HTMLSlotElement& slot = toHTMLSlotElement(*sibling); | 62 const HTMLSlotElement& slot = toHTMLSlotElement(*sibling); |
| 63 if (Node* found = (direction == TraversalDirectionForward ? slot.fir
stDistributedNode() : slot.lastDistributedNode())) | 63 if (Node* found = (direction == TraversalDirectionForward ? slot.fir
stDistributedNode() : slot.lastDistributedNode())) |
| 64 return found; | 64 return found; |
| 65 continue; | 65 continue; |
| 66 } | 66 } |
| 67 if (node->isInV0ShadowTree()) | 67 if (node->isInV0ShadowTree()) |
| 68 return v0ResolveDistributionStartingAt(*sibling, direction); | 68 return v0ResolveDistributionStartingAt(*sibling, direction); |
| 69 return const_cast<Node*>(sibling); | 69 return const_cast<Node*>(sibling); |
| 70 } | 70 } |
| 71 return nullptr; | 71 return nullptr; |
| 72 } | 72 } |
| 73 | 73 |
| 74 Node* ComposedTreeTraversal::v0ResolveDistributionStartingAt(const Node& node, T
raversalDirection direction) | 74 Node* FlatTreeTraversal::v0ResolveDistributionStartingAt(const Node& node, Trave
rsalDirection direction) |
| 75 { | 75 { |
| 76 ASSERT(!isHTMLSlotElement(node)); | 76 ASSERT(!isHTMLSlotElement(node)); |
| 77 for (const Node* sibling = &node; sibling; sibling = (direction == Traversal
DirectionForward ? sibling->nextSibling() : sibling->previousSibling())) { | 77 for (const Node* sibling = &node; sibling; sibling = (direction == Traversal
DirectionForward ? sibling->nextSibling() : sibling->previousSibling())) { |
| 78 if (!isActiveInsertionPoint(*sibling)) | 78 if (!isActiveInsertionPoint(*sibling)) |
| 79 return const_cast<Node*>(sibling); | 79 return const_cast<Node*>(sibling); |
| 80 const InsertionPoint& insertionPoint = toInsertionPoint(*sibling); | 80 const InsertionPoint& insertionPoint = toInsertionPoint(*sibling); |
| 81 if (Node* found = (direction == TraversalDirectionForward ? insertionPoi
nt.firstDistributedNode() : insertionPoint.lastDistributedNode())) | 81 if (Node* found = (direction == TraversalDirectionForward ? insertionPoi
nt.firstDistributedNode() : insertionPoint.lastDistributedNode())) |
| 82 return found; | 82 return found; |
| 83 ASSERT(isHTMLShadowElement(insertionPoint) || (isHTMLContentElement(inse
rtionPoint) && !insertionPoint.hasChildren())); | 83 ASSERT(isHTMLShadowElement(insertionPoint) || (isHTMLContentElement(inse
rtionPoint) && !insertionPoint.hasChildren())); |
| 84 } | 84 } |
| 85 return nullptr; | 85 return nullptr; |
| 86 } | 86 } |
| 87 | 87 |
| 88 static HTMLSlotElement* finalDestinationSlotFor(const Node& node) | 88 static HTMLSlotElement* finalDestinationSlotFor(const Node& node) |
| 89 { | 89 { |
| 90 HTMLSlotElement* slot = node.assignedSlot(); | 90 HTMLSlotElement* slot = node.assignedSlot(); |
| 91 if (!slot) | 91 if (!slot) |
| 92 return nullptr; | 92 return nullptr; |
| 93 for (HTMLSlotElement* next = slot->assignedSlot(); next; next = next->assign
edSlot()) { | 93 for (HTMLSlotElement* next = slot->assignedSlot(); next; next = next->assign
edSlot()) { |
| 94 slot = next; | 94 slot = next; |
| 95 } | 95 } |
| 96 return slot; | 96 return slot; |
| 97 } | 97 } |
| 98 | 98 |
| 99 // TODO(hayato): This may return a wrong result for a node which is not in a | 99 // TODO(hayato): This may return a wrong result for a node which is not in a |
| 100 // document composed tree. See ComposedTreeTraversalTest's redistribution test
for details. | 100 // document flat tree. See FlatTreeTraversalTest's redistribution test for deta
ils. |
| 101 Node* ComposedTreeTraversal::traverseSiblings(const Node& node, TraversalDirecti
on direction) | 101 Node* FlatTreeTraversal::traverseSiblings(const Node& node, TraversalDirection d
irection) |
| 102 { | 102 { |
| 103 if (node.isChildOfV1ShadowHost()) | 103 if (node.isChildOfV1ShadowHost()) |
| 104 return traverseSiblingsForV1HostChild(node, direction); | 104 return traverseSiblingsForV1HostChild(node, direction); |
| 105 | 105 |
| 106 if (shadowWhereNodeCanBeDistributed(node)) | 106 if (shadowWhereNodeCanBeDistributed(node)) |
| 107 return traverseSiblingsForV0Distribution(node, direction); | 107 return traverseSiblingsForV0Distribution(node, direction); |
| 108 | 108 |
| 109 if (Node* found = resolveDistributionStartingAt(direction == TraversalDirect
ionForward ? node.nextSibling() : node.previousSibling(), direction)) | 109 if (Node* found = resolveDistributionStartingAt(direction == TraversalDirect
ionForward ? node.nextSibling() : node.previousSibling(), direction)) |
| 110 return found; | 110 return found; |
| 111 | 111 |
| 112 if (!node.isInV0ShadowTree()) | 112 if (!node.isInV0ShadowTree()) |
| 113 return nullptr; | 113 return nullptr; |
| 114 | 114 |
| 115 // For v0 older shadow tree | 115 // For v0 older shadow tree |
| 116 if (node.parentNode() && node.parentNode()->isShadowRoot()) { | 116 if (node.parentNode() && node.parentNode()->isShadowRoot()) { |
| 117 ShadowRoot* parentShadowRoot = toShadowRoot(node.parentNode()); | 117 ShadowRoot* parentShadowRoot = toShadowRoot(node.parentNode()); |
| 118 if (!parentShadowRoot->isYoungest()) { | 118 if (!parentShadowRoot->isYoungest()) { |
| 119 HTMLShadowElement* assignedInsertionPoint = parentShadowRoot->shadow
InsertionPointOfYoungerShadowRoot(); | 119 HTMLShadowElement* assignedInsertionPoint = parentShadowRoot->shadow
InsertionPointOfYoungerShadowRoot(); |
| 120 ASSERT(assignedInsertionPoint); | 120 ASSERT(assignedInsertionPoint); |
| 121 return traverseSiblings(*assignedInsertionPoint, direction); | 121 return traverseSiblings(*assignedInsertionPoint, direction); |
| 122 } | 122 } |
| 123 } | 123 } |
| 124 return nullptr; | 124 return nullptr; |
| 125 } | 125 } |
| 126 | 126 |
| 127 Node* ComposedTreeTraversal::traverseSiblingsForV1HostChild(const Node& node, Tr
aversalDirection direction) | 127 Node* FlatTreeTraversal::traverseSiblingsForV1HostChild(const Node& node, Traver
salDirection direction) |
| 128 { | 128 { |
| 129 HTMLSlotElement* slot = finalDestinationSlotFor(node); | 129 HTMLSlotElement* slot = finalDestinationSlotFor(node); |
| 130 if (!slot) | 130 if (!slot) |
| 131 return nullptr; | 131 return nullptr; |
| 132 if (Node* siblingInDistributedNodes = (direction == TraversalDirectionForwar
d ? slot->distributedNodeNextTo(node) : slot->distributedNodePreviousTo(node))) | 132 if (Node* siblingInDistributedNodes = (direction == TraversalDirectionForwar
d ? slot->distributedNodeNextTo(node) : slot->distributedNodePreviousTo(node))) |
| 133 return siblingInDistributedNodes; | 133 return siblingInDistributedNodes; |
| 134 return traverseSiblings(*slot, direction); | 134 return traverseSiblings(*slot, direction); |
| 135 } | 135 } |
| 136 | 136 |
| 137 Node* ComposedTreeTraversal::traverseSiblingsForV0Distribution(const Node& node,
TraversalDirection direction) | 137 Node* FlatTreeTraversal::traverseSiblingsForV0Distribution(const Node& node, Tra
versalDirection direction) |
| 138 { | 138 { |
| 139 const InsertionPoint* finalDestination = resolveReprojection(&node); | 139 const InsertionPoint* finalDestination = resolveReprojection(&node); |
| 140 if (!finalDestination) | 140 if (!finalDestination) |
| 141 return nullptr; | 141 return nullptr; |
| 142 if (Node* found = (direction == TraversalDirectionForward ? finalDestination
->distributedNodeNextTo(&node) : finalDestination->distributedNodePreviousTo(&no
de))) | 142 if (Node* found = (direction == TraversalDirectionForward ? finalDestination
->distributedNodeNextTo(&node) : finalDestination->distributedNodePreviousTo(&no
de))) |
| 143 return found; | 143 return found; |
| 144 return traverseSiblings(*finalDestination, direction); | 144 return traverseSiblings(*finalDestination, direction); |
| 145 | 145 |
| 146 } | 146 } |
| 147 | 147 |
| 148 ContainerNode* ComposedTreeTraversal::traverseParent(const Node& node, ParentTra
versalDetails* details) | 148 ContainerNode* FlatTreeTraversal::traverseParent(const Node& node, ParentTravers
alDetails* details) |
| 149 { | 149 { |
| 150 // TODO(hayato): Stop this hack for a pseudo element because a pseudo elemen
t is not a child of its parentOrShadowHostNode() in a composed tree. | 150 // TODO(hayato): Stop this hack for a pseudo element because a pseudo elemen
t is not a child of its parentOrShadowHostNode() in a flat tree. |
| 151 if (node.isPseudoElement()) | 151 if (node.isPseudoElement()) |
| 152 return node.parentOrShadowHostNode(); | 152 return node.parentOrShadowHostNode(); |
| 153 | 153 |
| 154 if (node.isChildOfV1ShadowHost()) { | 154 if (node.isChildOfV1ShadowHost()) { |
| 155 HTMLSlotElement* slot = finalDestinationSlotFor(node); | 155 HTMLSlotElement* slot = finalDestinationSlotFor(node); |
| 156 if (!slot) | 156 if (!slot) |
| 157 return nullptr; | 157 return nullptr; |
| 158 return traverseParent(*slot); | 158 return traverseParent(*slot); |
| 159 } | 159 } |
| 160 | 160 |
| 161 Element* parent = node.parentElement(); | 161 Element* parent = node.parentElement(); |
| 162 if (parent && isHTMLSlotElement(parent)) { | 162 if (parent && isHTMLSlotElement(parent)) { |
| 163 HTMLSlotElement& slot = toHTMLSlotElement(*parent); | 163 HTMLSlotElement& slot = toHTMLSlotElement(*parent); |
| 164 if (!slot.getAssignedNodes().isEmpty()) | 164 if (!slot.getAssignedNodes().isEmpty()) |
| 165 return nullptr; | 165 return nullptr; |
| 166 return traverseParent(slot, details); | 166 return traverseParent(slot, details); |
| 167 } | 167 } |
| 168 | 168 |
| 169 if (canBeDistributedToInsertionPoint(node)) | 169 if (canBeDistributedToInsertionPoint(node)) |
| 170 return traverseParentForV0(node, details); | 170 return traverseParentForV0(node, details); |
| 171 | 171 |
| 172 ASSERT(!shadowWhereNodeCanBeDistributed(node)); | 172 ASSERT(!shadowWhereNodeCanBeDistributed(node)); |
| 173 return traverseParentOrHost(node); | 173 return traverseParentOrHost(node); |
| 174 } | 174 } |
| 175 | 175 |
| 176 ContainerNode* ComposedTreeTraversal::traverseParentForV0(const Node& node, Pare
ntTraversalDetails* details) | 176 ContainerNode* FlatTreeTraversal::traverseParentForV0(const Node& node, ParentTr
aversalDetails* details) |
| 177 { | 177 { |
| 178 if (shadowWhereNodeCanBeDistributed(node)) { | 178 if (shadowWhereNodeCanBeDistributed(node)) { |
| 179 if (const InsertionPoint* insertionPoint = resolveReprojection(&node)) { | 179 if (const InsertionPoint* insertionPoint = resolveReprojection(&node)) { |
| 180 if (details) | 180 if (details) |
| 181 details->didTraverseInsertionPoint(insertionPoint); | 181 details->didTraverseInsertionPoint(insertionPoint); |
| 182 // The node is distributed. But the distribution was stopped at this
insertion point. | 182 // The node is distributed. But the distribution was stopped at this
insertion point. |
| 183 if (shadowWhereNodeCanBeDistributed(*insertionPoint)) | 183 if (shadowWhereNodeCanBeDistributed(*insertionPoint)) |
| 184 return nullptr; | 184 return nullptr; |
| 185 return traverseParent(*insertionPoint); | 185 return traverseParent(*insertionPoint); |
| 186 } | 186 } |
| 187 return nullptr; | 187 return nullptr; |
| 188 } | 188 } |
| 189 ContainerNode* parent = traverseParentOrHost(node); | 189 ContainerNode* parent = traverseParentOrHost(node); |
| 190 if (isActiveInsertionPoint(*parent)) | 190 if (isActiveInsertionPoint(*parent)) |
| 191 return nullptr; | 191 return nullptr; |
| 192 return parent; | 192 return parent; |
| 193 } | 193 } |
| 194 | 194 |
| 195 ContainerNode* ComposedTreeTraversal::traverseParentOrHost(const Node& node) | 195 ContainerNode* FlatTreeTraversal::traverseParentOrHost(const Node& node) |
| 196 { | 196 { |
| 197 ContainerNode* parent = node.parentNode(); | 197 ContainerNode* parent = node.parentNode(); |
| 198 if (!parent) | 198 if (!parent) |
| 199 return nullptr; | 199 return nullptr; |
| 200 if (!parent->isShadowRoot()) | 200 if (!parent->isShadowRoot()) |
| 201 return parent; | 201 return parent; |
| 202 ShadowRoot* shadowRoot = toShadowRoot(parent); | 202 ShadowRoot* shadowRoot = toShadowRoot(parent); |
| 203 ASSERT(!shadowRoot->shadowInsertionPointOfYoungerShadowRoot()); | 203 ASSERT(!shadowRoot->shadowInsertionPointOfYoungerShadowRoot()); |
| 204 if (!shadowRoot->isYoungest()) | 204 if (!shadowRoot->isYoungest()) |
| 205 return nullptr; | 205 return nullptr; |
| 206 return shadowRoot->host(); | 206 return shadowRoot->host(); |
| 207 } | 207 } |
| 208 | 208 |
| 209 Node* ComposedTreeTraversal::childAt(const Node& node, unsigned index) | 209 Node* FlatTreeTraversal::childAt(const Node& node, unsigned index) |
| 210 { | 210 { |
| 211 assertPrecondition(node); | 211 assertPrecondition(node); |
| 212 Node* child = traverseFirstChild(node); | 212 Node* child = traverseFirstChild(node); |
| 213 while (child && index--) | 213 while (child && index--) |
| 214 child = nextSibling(*child); | 214 child = nextSibling(*child); |
| 215 assertPostcondition(child); | 215 assertPostcondition(child); |
| 216 return child; | 216 return child; |
| 217 } | 217 } |
| 218 | 218 |
| 219 Node* ComposedTreeTraversal::nextSkippingChildren(const Node& node) | 219 Node* FlatTreeTraversal::nextSkippingChildren(const Node& node) |
| 220 { | 220 { |
| 221 if (Node* nextSibling = traverseNextSibling(node)) | 221 if (Node* nextSibling = traverseNextSibling(node)) |
| 222 return nextSibling; | 222 return nextSibling; |
| 223 return traverseNextAncestorSibling(node); | 223 return traverseNextAncestorSibling(node); |
| 224 } | 224 } |
| 225 | 225 |
| 226 bool ComposedTreeTraversal::containsIncludingPseudoElement(const ContainerNode&
container, const Node& node) | 226 bool FlatTreeTraversal::containsIncludingPseudoElement(const ContainerNode& cont
ainer, const Node& node) |
| 227 { | 227 { |
| 228 assertPrecondition(container); | 228 assertPrecondition(container); |
| 229 assertPrecondition(node); | 229 assertPrecondition(node); |
| 230 // This can be slower than ComposedTreeTraversal::contains() because we | 230 // This can be slower than FlatTreeTraversal::contains() because we |
| 231 // can't early exit even when container doesn't have children. | 231 // can't early exit even when container doesn't have children. |
| 232 for (const Node* current = &node; current; current = traverseParent(*current
)) { | 232 for (const Node* current = &node; current; current = traverseParent(*current
)) { |
| 233 if (current == &container) | 233 if (current == &container) |
| 234 return true; | 234 return true; |
| 235 } | 235 } |
| 236 return false; | 236 return false; |
| 237 } | 237 } |
| 238 | 238 |
| 239 Node* ComposedTreeTraversal::previousSkippingChildren(const Node& node) | 239 Node* FlatTreeTraversal::previousSkippingChildren(const Node& node) |
| 240 { | 240 { |
| 241 if (Node* previousSibling = traversePreviousSibling(node)) | 241 if (Node* previousSibling = traversePreviousSibling(node)) |
| 242 return previousSibling; | 242 return previousSibling; |
| 243 return traversePreviousAncestorSibling(node); | 243 return traversePreviousAncestorSibling(node); |
| 244 } | 244 } |
| 245 | 245 |
| 246 static Node* previousAncestorSiblingPostOrder(const Node& current, const Node* s
tayWithin) | 246 static Node* previousAncestorSiblingPostOrder(const Node& current, const Node* s
tayWithin) |
| 247 { | 247 { |
| 248 ASSERT(!ComposedTreeTraversal::previousSibling(current)); | 248 ASSERT(!FlatTreeTraversal::previousSibling(current)); |
| 249 for (Node* parent = ComposedTreeTraversal::parent(current); parent; parent =
ComposedTreeTraversal::parent(*parent)) { | 249 for (Node* parent = FlatTreeTraversal::parent(current); parent; parent = Fla
tTreeTraversal::parent(*parent)) { |
| 250 if (parent == stayWithin) | 250 if (parent == stayWithin) |
| 251 return nullptr; | 251 return nullptr; |
| 252 if (Node* previousSibling = ComposedTreeTraversal::previousSibling(*pare
nt)) | 252 if (Node* previousSibling = FlatTreeTraversal::previousSibling(*parent)) |
| 253 return previousSibling; | 253 return previousSibling; |
| 254 } | 254 } |
| 255 return nullptr; | 255 return nullptr; |
| 256 } | 256 } |
| 257 | 257 |
| 258 // TODO(yosin) We should consider introducing template class to share code | 258 // TODO(yosin) We should consider introducing template class to share code |
| 259 // between DOM tree traversal and composed tree tarversal. | 259 // between DOM tree traversal and flat tree tarversal. |
| 260 Node* ComposedTreeTraversal::previousPostOrder(const Node& current, const Node*
stayWithin) | 260 Node* FlatTreeTraversal::previousPostOrder(const Node& current, const Node* stay
Within) |
| 261 { | 261 { |
| 262 assertPrecondition(current); | 262 assertPrecondition(current); |
| 263 if (stayWithin) | 263 if (stayWithin) |
| 264 assertPrecondition(*stayWithin); | 264 assertPrecondition(*stayWithin); |
| 265 if (Node* lastChild = traverseLastChild(current)) { | 265 if (Node* lastChild = traverseLastChild(current)) { |
| 266 assertPostcondition(lastChild); | 266 assertPostcondition(lastChild); |
| 267 return lastChild; | 267 return lastChild; |
| 268 } | 268 } |
| 269 if (current == stayWithin) | 269 if (current == stayWithin) |
| 270 return nullptr; | 270 return nullptr; |
| 271 if (Node* previousSibling = traversePreviousSibling(current)) { | 271 if (Node* previousSibling = traversePreviousSibling(current)) { |
| 272 assertPostcondition(previousSibling); | 272 assertPostcondition(previousSibling); |
| 273 return previousSibling; | 273 return previousSibling; |
| 274 } | 274 } |
| 275 return previousAncestorSiblingPostOrder(current, stayWithin); | 275 return previousAncestorSiblingPostOrder(current, stayWithin); |
| 276 } | 276 } |
| 277 | 277 |
| 278 bool ComposedTreeTraversal::isDescendantOf(const Node& node, const Node& other) | 278 bool FlatTreeTraversal::isDescendantOf(const Node& node, const Node& other) |
| 279 { | 279 { |
| 280 assertPrecondition(node); | 280 assertPrecondition(node); |
| 281 assertPrecondition(other); | 281 assertPrecondition(other); |
| 282 if (!hasChildren(other) || node.inDocument() != other.inDocument()) | 282 if (!hasChildren(other) || node.inDocument() != other.inDocument()) |
| 283 return false; | 283 return false; |
| 284 for (const ContainerNode* n = traverseParent(node); n; n = traverseParent(*n
)) { | 284 for (const ContainerNode* n = traverseParent(node); n; n = traverseParent(*n
)) { |
| 285 if (n == other) | 285 if (n == other) |
| 286 return true; | 286 return true; |
| 287 } | 287 } |
| 288 return false; | 288 return false; |
| 289 } | 289 } |
| 290 | 290 |
| 291 Node* ComposedTreeTraversal::commonAncestor(const Node& nodeA, const Node& nodeB
) | 291 Node* FlatTreeTraversal::commonAncestor(const Node& nodeA, const Node& nodeB) |
| 292 { | 292 { |
| 293 assertPrecondition(nodeA); | 293 assertPrecondition(nodeA); |
| 294 assertPrecondition(nodeB); | 294 assertPrecondition(nodeB); |
| 295 Node* result = nodeA.commonAncestor(nodeB, | 295 Node* result = nodeA.commonAncestor(nodeB, |
| 296 [](const Node& node) | 296 [](const Node& node) |
| 297 { | 297 { |
| 298 return ComposedTreeTraversal::parent(node); | 298 return FlatTreeTraversal::parent(node); |
| 299 }); | 299 }); |
| 300 assertPostcondition(result); | 300 assertPostcondition(result); |
| 301 return result; | 301 return result; |
| 302 } | 302 } |
| 303 | 303 |
| 304 Node* ComposedTreeTraversal::traverseNextAncestorSibling(const Node& node) | 304 Node* FlatTreeTraversal::traverseNextAncestorSibling(const Node& node) |
| 305 { | 305 { |
| 306 ASSERT(!traverseNextSibling(node)); | 306 ASSERT(!traverseNextSibling(node)); |
| 307 for (Node* parent = traverseParent(node); parent; parent = traverseParent(*p
arent)) { | 307 for (Node* parent = traverseParent(node); parent; parent = traverseParent(*p
arent)) { |
| 308 if (Node* nextSibling = traverseNextSibling(*parent)) | 308 if (Node* nextSibling = traverseNextSibling(*parent)) |
| 309 return nextSibling; | 309 return nextSibling; |
| 310 } | 310 } |
| 311 return nullptr; | 311 return nullptr; |
| 312 } | 312 } |
| 313 | 313 |
| 314 Node* ComposedTreeTraversal::traversePreviousAncestorSibling(const Node& node) | 314 Node* FlatTreeTraversal::traversePreviousAncestorSibling(const Node& node) |
| 315 { | 315 { |
| 316 ASSERT(!traversePreviousSibling(node)); | 316 ASSERT(!traversePreviousSibling(node)); |
| 317 for (Node* parent = traverseParent(node); parent; parent = traverseParent(*p
arent)) { | 317 for (Node* parent = traverseParent(node); parent; parent = traverseParent(*p
arent)) { |
| 318 if (Node* previousSibling = traversePreviousSibling(*parent)) | 318 if (Node* previousSibling = traversePreviousSibling(*parent)) |
| 319 return previousSibling; | 319 return previousSibling; |
| 320 } | 320 } |
| 321 return nullptr; | 321 return nullptr; |
| 322 } | 322 } |
| 323 | 323 |
| 324 unsigned ComposedTreeTraversal::index(const Node& node) | 324 unsigned FlatTreeTraversal::index(const Node& node) |
| 325 { | 325 { |
| 326 assertPrecondition(node); | 326 assertPrecondition(node); |
| 327 unsigned count = 0; | 327 unsigned count = 0; |
| 328 for (Node* runner = traversePreviousSibling(node); runner; runner = previous
Sibling(*runner)) | 328 for (Node* runner = traversePreviousSibling(node); runner; runner = previous
Sibling(*runner)) |
| 329 ++count; | 329 ++count; |
| 330 return count; | 330 return count; |
| 331 } | 331 } |
| 332 | 332 |
| 333 unsigned ComposedTreeTraversal::countChildren(const Node& node) | 333 unsigned FlatTreeTraversal::countChildren(const Node& node) |
| 334 { | 334 { |
| 335 assertPrecondition(node); | 335 assertPrecondition(node); |
| 336 unsigned count = 0; | 336 unsigned count = 0; |
| 337 for (Node* runner = traverseFirstChild(node); runner; runner = traverseNextS
ibling(*runner)) | 337 for (Node* runner = traverseFirstChild(node); runner; runner = traverseNextS
ibling(*runner)) |
| 338 ++count; | 338 ++count; |
| 339 return count; | 339 return count; |
| 340 } | 340 } |
| 341 | 341 |
| 342 Node* ComposedTreeTraversal::lastWithin(const Node& node) | 342 Node* FlatTreeTraversal::lastWithin(const Node& node) |
| 343 { | 343 { |
| 344 assertPrecondition(node); | 344 assertPrecondition(node); |
| 345 Node* descendant = traverseLastChild(node); | 345 Node* descendant = traverseLastChild(node); |
| 346 for (Node* child = descendant; child; child = lastChild(*child)) | 346 for (Node* child = descendant; child; child = lastChild(*child)) |
| 347 descendant = child; | 347 descendant = child; |
| 348 assertPostcondition(descendant); | 348 assertPostcondition(descendant); |
| 349 return descendant; | 349 return descendant; |
| 350 } | 350 } |
| 351 | 351 |
| 352 Node& ComposedTreeTraversal::lastWithinOrSelf(const Node& node) | 352 Node& FlatTreeTraversal::lastWithinOrSelf(const Node& node) |
| 353 { | 353 { |
| 354 assertPrecondition(node); | 354 assertPrecondition(node); |
| 355 Node* lastDescendant = lastWithin(node); | 355 Node* lastDescendant = lastWithin(node); |
| 356 Node& result = lastDescendant ? *lastDescendant : const_cast<Node&>(node); | 356 Node& result = lastDescendant ? *lastDescendant : const_cast<Node&>(node); |
| 357 assertPostcondition(&result); | 357 assertPostcondition(&result); |
| 358 return result; | 358 return result; |
| 359 } | 359 } |
| 360 | 360 |
| 361 } // namespace blink | 361 } // namespace blink |
| OLD | NEW |