| 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 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 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 "config.h" | 27 #include "config.h" |
| 28 #include "core/dom/shadow/ComposedTreeTraversal.h" | 28 #include "core/dom/shadow/ComposedTreeTraversal.h" |
| 29 | 29 |
| 30 #include "core/dom/Element.h" | 30 #include "core/dom/Element.h" |
| 31 #include "core/dom/shadow/ElementShadow.h" | 31 #include "core/dom/shadow/ElementShadow.h" |
| 32 #include "core/html/HTMLShadowElement.h" | 32 #include "core/html/HTMLShadowElement.h" |
| 33 #include "core/html/HTMLSlotElement.h" |
| 33 | 34 |
| 34 namespace blink { | 35 namespace blink { |
| 35 | 36 |
| 36 static inline ElementShadow* shadowFor(const Node& node) | 37 static inline ElementShadow* shadowFor(const Node& node) |
| 37 { | 38 { |
| 38 return node.isElementNode() ? toElement(node).shadow() : nullptr; | 39 return node.isElementNode() ? toElement(node).shadow() : nullptr; |
| 39 } | 40 } |
| 40 | 41 |
| 41 Node* ComposedTreeTraversal::traverseChild(const Node& node, TraversalDirection
direction) | 42 Node* ComposedTreeTraversal::traverseChild(const Node& node, TraversalDirection
direction) |
| 42 { | 43 { |
| 43 ElementShadow* shadow = shadowFor(node); | 44 ElementShadow* shadow = shadowFor(node); |
| 44 if (shadow) { | 45 if (shadow) { |
| 45 ShadowRoot& shadowRoot = shadow->youngestShadowRoot(); | 46 ShadowRoot& shadowRoot = shadow->youngestShadowRoot(); |
| 46 return resolveDistributionStartingAt(direction == TraversalDirectionForw
ard ? shadowRoot.firstChild() : shadowRoot.lastChild(), direction); | 47 return resolveDistributionStartingAt(direction == TraversalDirectionForw
ard ? shadowRoot.firstChild() : shadowRoot.lastChild(), direction); |
| 47 } | 48 } |
| 48 return resolveDistributionStartingAt(direction == TraversalDirectionForward
? node.firstChild() : node.lastChild(), direction); | 49 return resolveDistributionStartingAt(direction == TraversalDirectionForward
? node.firstChild() : node.lastChild(), direction); |
| 49 } | 50 } |
| 50 | 51 |
| 51 Node* ComposedTreeTraversal::resolveDistributionStartingAt(const Node* node, Tra
versalDirection direction) | 52 Node* ComposedTreeTraversal::resolveDistributionStartingAt(const Node* node, Tra
versalDirection direction) |
| 52 { | 53 { |
| 53 for (const Node* sibling = node; sibling; sibling = (direction == TraversalD
irectionForward ? sibling->nextSibling() : sibling->previousSibling())) { | 54 if (!node) |
| 55 return nullptr; |
| 56 if (node->isInShadowTree() && node->containingShadowRoot()->isV1()) |
| 57 return v1ResolveDistributionStartingAt(*node, direction); |
| 58 return v0ResolveDistributionStartingAt(*node, direction); |
| 59 } |
| 60 |
| 61 Node* ComposedTreeTraversal::v0ResolveDistributionStartingAt(const Node& node, T
raversalDirection direction) |
| 62 { |
| 63 for (const Node* sibling = &node; sibling; sibling = (direction == Traversal
DirectionForward ? sibling->nextSibling() : sibling->previousSibling())) { |
| 54 if (!isActiveInsertionPoint(*sibling)) | 64 if (!isActiveInsertionPoint(*sibling)) |
| 55 return const_cast<Node*>(sibling); | 65 return const_cast<Node*>(sibling); |
| 56 const InsertionPoint& insertionPoint = toInsertionPoint(*sibling); | 66 const InsertionPoint& insertionPoint = toInsertionPoint(*sibling); |
| 57 if (Node* found = (direction == TraversalDirectionForward ? insertionPoi
nt.firstDistributedNode() : insertionPoint.lastDistributedNode())) | 67 if (Node* found = (direction == TraversalDirectionForward ? insertionPoi
nt.firstDistributedNode() : insertionPoint.lastDistributedNode())) |
| 58 return found; | 68 return found; |
| 59 ASSERT(isHTMLShadowElement(insertionPoint) || (isHTMLContentElement(inse
rtionPoint) && !insertionPoint.hasChildren())); | 69 ASSERT(isHTMLShadowElement(insertionPoint) || (isHTMLContentElement(inse
rtionPoint) && !insertionPoint.hasChildren())); |
| 60 } | 70 } |
| 61 return nullptr; | 71 return nullptr; |
| 62 } | 72 } |
| 63 | 73 |
| 74 Node* ComposedTreeTraversal::v1ResolveDistributionStartingAt(const Node& node, T
raversalDirection direction) |
| 75 { |
| 76 for (const Node* sibling = &node; sibling; sibling = (direction == Traversal
DirectionForward ? sibling->nextSibling() : sibling->previousSibling())) { |
| 77 if (!isHTMLSlotElement(*sibling)) |
| 78 return const_cast<Node*>(sibling); |
| 79 const HTMLSlotElement& slot = toHTMLSlotElement(*sibling); |
| 80 if (Node* found = (direction == TraversalDirectionForward ? slot.firstDi
stributedNode() : slot.lastDistributedNode())) |
| 81 return found; |
| 82 } |
| 83 return nullptr; |
| 84 } |
| 85 |
| 86 static HTMLSlotElement* finalDestinationSlotFor(const Node& node) |
| 87 { |
| 88 HTMLSlotElement* slot = node.assignedSlot(); |
| 89 if (!slot) |
| 90 return nullptr; |
| 91 for (HTMLSlotElement* next = slot->assignedSlot(); next; next = next->assign
edSlot()) { |
| 92 slot = next; |
| 93 } |
| 94 return slot; |
| 95 } |
| 96 |
| 97 Node* ComposedTreeTraversal::traverseSiblings(const Node& node, TraversalDirecti
on direction) |
| 98 { |
| 99 Node* parent = node.parentNode(); |
| 100 if (!parent) |
| 101 return nullptr; |
| 102 if (parent->isElementNode()) { |
| 103 if (ElementShadow* shadow = toElement(parent)->shadow()) { |
| 104 if (shadow->isV1()) { |
| 105 return v1TraverseSiblings(node, direction); |
| 106 } |
| 107 } |
| 108 } |
| 109 return v0TraverseSiblings(node, direction); |
| 110 } |
| 111 |
| 64 // TODO(hayato): This may return a wrong result for a node which is not in a | 112 // TODO(hayato): This may return a wrong result for a node which is not in a |
| 65 // document composed tree. See ComposedTreeTraversalTest's redistribution test
for details. | 113 // document composed tree. See ComposedTreeTraversalTest's redistribution test
for details. |
| 66 Node* ComposedTreeTraversal::traverseSiblings(const Node& node, TraversalDirecti
on direction) | 114 Node* ComposedTreeTraversal::v0TraverseSiblings(const Node& node, TraversalDirec
tion direction) |
| 67 { | 115 { |
| 68 if (!shadowWhereNodeCanBeDistributed(node)) | 116 if (!shadowWhereNodeCanBeDistributed(node)) |
| 69 return traverseSiblingsOrShadowInsertionPointSiblings(node, direction); | 117 return traverseSiblingsOrShadowInsertionPointSiblings(node, direction); |
| 70 | 118 |
| 71 const InsertionPoint* finalDestination = resolveReprojection(&node); | 119 const InsertionPoint* finalDestination = resolveReprojection(&node); |
| 72 if (!finalDestination) | 120 if (!finalDestination) |
| 73 return nullptr; | 121 return nullptr; |
| 74 if (Node* found = (direction == TraversalDirectionForward ? finalDestination
->distributedNodeNextTo(&node) : finalDestination->distributedNodePreviousTo(&no
de))) | 122 if (Node* found = (direction == TraversalDirectionForward ? finalDestination
->distributedNodeNextTo(&node) : finalDestination->distributedNodePreviousTo(&no
de))) |
| 75 return found; | 123 return found; |
| 76 return traverseSiblings(*finalDestination, direction); | 124 return traverseSiblings(*finalDestination, direction); |
| 77 } | 125 } |
| 78 | 126 |
| 127 Node* ComposedTreeTraversal::v1TraverseSiblings(const Node& node, TraversalDirec
tion direction) |
| 128 { |
| 129 HTMLSlotElement* slot = finalDestinationSlotFor(node); |
| 130 if (!slot) |
| 131 return resolveDistributionStartingAt(direction == TraversalDirectionForw
ard ? node.nextSibling() : node.previousSibling(), direction); |
| 132 if (Node* siblingInDistributedNodes = (direction == TraversalDirectionForwar
d ? slot->distributedNodeNextTo(node) : slot->distributedNodePreviousTo(node))) |
| 133 return siblingInDistributedNodes; |
| 134 return v1TraverseSiblings(*slot, direction); |
| 135 } |
| 136 |
| 79 Node* ComposedTreeTraversal::traverseSiblingsOrShadowInsertionPointSiblings(cons
t Node& node, TraversalDirection direction) | 137 Node* ComposedTreeTraversal::traverseSiblingsOrShadowInsertionPointSiblings(cons
t Node& node, TraversalDirection direction) |
| 80 { | 138 { |
| 81 if (Node* found = resolveDistributionStartingAt(direction == TraversalDirect
ionForward ? node.nextSibling() : node.previousSibling(), direction)) | 139 if (Node* found = resolveDistributionStartingAt(direction == TraversalDirect
ionForward ? node.nextSibling() : node.previousSibling(), direction)) |
| 82 return found; | 140 return found; |
| 83 | 141 |
| 84 if (node.parentNode() && node.parentNode()->isShadowRoot()) { | 142 if (node.parentNode() && node.parentNode()->isShadowRoot()) { |
| 85 ShadowRoot* parentShadowRoot = toShadowRoot(node.parentNode()); | 143 ShadowRoot* parentShadowRoot = toShadowRoot(node.parentNode()); |
| 86 if (!parentShadowRoot->isYoungest()) { | 144 if (!parentShadowRoot->isYoungest()) { |
| 87 HTMLShadowElement* assignedInsertionPoint = parentShadowRoot->shadow
InsertionPointOfYoungerShadowRoot(); | 145 HTMLShadowElement* assignedInsertionPoint = parentShadowRoot->shadow
InsertionPointOfYoungerShadowRoot(); |
| 88 ASSERT(assignedInsertionPoint); | 146 ASSERT(assignedInsertionPoint); |
| 89 return traverseSiblingsOrShadowInsertionPointSiblings(*assignedInser
tionPoint, direction); | 147 return traverseSiblingsOrShadowInsertionPointSiblings(*assignedInser
tionPoint, direction); |
| 90 } | 148 } |
| 91 } | 149 } |
| 92 return nullptr; | 150 return nullptr; |
| 93 } | 151 } |
| 94 | 152 |
| 95 // FIXME: Use an iterative algorithm so that it can be inlined. | 153 static ElementShadow* parentElementShadow(const Node& node) |
| 96 // https://bugs.webkit.org/show_bug.cgi?id=90415 | 154 { |
| 155 Node* parent = node.parentNode(); |
| 156 if (!parent) |
| 157 return nullptr; |
| 158 if (parent->isElementNode()) |
| 159 return toElement(parent)->shadow(); |
| 160 return nullptr; |
| 161 } |
| 162 |
| 97 ContainerNode* ComposedTreeTraversal::traverseParent(const Node& node, ParentTra
versalDetails* details) | 163 ContainerNode* ComposedTreeTraversal::traverseParent(const Node& node, ParentTra
versalDetails* details) |
| 98 { | 164 { |
| 99 // 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. | 165 // 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. |
| 100 if (node.isPseudoElement()) | 166 if (node.isPseudoElement()) |
| 101 return node.parentOrShadowHostNode(); | 167 return node.parentOrShadowHostNode(); |
| 102 | 168 |
| 103 if (shadowWhereNodeCanBeDistributed(node)) { | 169 ElementShadow* shadow = parentElementShadow(node); |
| 104 if (const InsertionPoint* insertionPoint = resolveReprojection(&node)) { | 170 if (shadow && shadow->isV1()) |
| 105 if (details) | 171 return v1TraverseParent(node); |
| 106 details->didTraverseInsertionPoint(insertionPoint); | 172 if (shadowWhereNodeCanBeDistributed(node)) |
| 107 // The node is distributed. But the distribution was stopped at this
insertion point. | 173 return v0TraverseParent(node, details); |
| 108 if (shadowWhereNodeCanBeDistributed(*insertionPoint)) | 174 return traverseParentOrHost(node); |
| 109 return nullptr; | 175 } |
| 110 return traverseParentOrHost(*insertionPoint); | 176 |
| 111 } | 177 ContainerNode* ComposedTreeTraversal::v1TraverseParent(const Node& node) |
| 178 { |
| 179 HTMLSlotElement* slot = finalDestinationSlotFor(node); |
| 180 if (!slot) |
| 181 return nullptr; |
| 182 if (parentElementShadow(*slot)) { |
| 183 // The node is distributed to the |slot|, however, |slot|, which is a |
| 184 // child of a shadow host, is not assigned to any slots. |
| 112 return nullptr; | 185 return nullptr; |
| 113 } | 186 } |
| 114 return traverseParentOrHost(node); | 187 return traverseParentOrHost(*slot); |
| 188 } |
| 189 |
| 190 ContainerNode* ComposedTreeTraversal::v0TraverseParent(const Node& node, ParentT
raversalDetails* details) |
| 191 { |
| 192 if (const InsertionPoint* insertionPoint = resolveReprojection(&node)) { |
| 193 if (details) |
| 194 details->didTraverseInsertionPoint(insertionPoint); |
| 195 // The node is distributed. But the distribution was stopped at this ins
ertion point. |
| 196 if (shadowWhereNodeCanBeDistributed(*insertionPoint)) |
| 197 return nullptr; |
| 198 return traverseParentOrHost(*insertionPoint); |
| 199 } |
| 200 return nullptr; |
| 115 } | 201 } |
| 116 | 202 |
| 117 inline ContainerNode* ComposedTreeTraversal::traverseParentOrHost(const Node& no
de) | 203 inline ContainerNode* ComposedTreeTraversal::traverseParentOrHost(const Node& no
de) |
| 118 { | 204 { |
| 205 // TODO(hayato): Support fallback contents of slots. The parent can be a slo
t. |
| 119 ContainerNode* parent = node.parentNode(); | 206 ContainerNode* parent = node.parentNode(); |
| 120 if (!parent) | 207 if (!parent) |
| 121 return nullptr; | 208 return nullptr; |
| 122 if (!parent->isShadowRoot()) | 209 if (!parent->isShadowRoot()) |
| 123 return parent; | 210 return parent; |
| 124 ShadowRoot* shadowRoot = toShadowRoot(parent); | 211 ShadowRoot* shadowRoot = toShadowRoot(parent); |
| 125 ASSERT(!shadowRoot->shadowInsertionPointOfYoungerShadowRoot()); | 212 ASSERT(!shadowRoot->shadowInsertionPointOfYoungerShadowRoot()); |
| 126 if (!shadowRoot->isYoungest()) | 213 if (!shadowRoot->isYoungest()) |
| 127 return nullptr; | 214 return nullptr; |
| 128 Element* host = shadowRoot->host(); | 215 Element* host = shadowRoot->host(); |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 277 Node& ComposedTreeTraversal::lastWithinOrSelf(const Node& node) | 364 Node& ComposedTreeTraversal::lastWithinOrSelf(const Node& node) |
| 278 { | 365 { |
| 279 assertPrecondition(node); | 366 assertPrecondition(node); |
| 280 Node* lastDescendant = lastWithin(node); | 367 Node* lastDescendant = lastWithin(node); |
| 281 Node& result = lastDescendant ? *lastDescendant : const_cast<Node&>(node); | 368 Node& result = lastDescendant ? *lastDescendant : const_cast<Node&>(node); |
| 282 assertPostcondition(&result); | 369 assertPostcondition(&result); |
| 283 return result; | 370 return result; |
| 284 } | 371 } |
| 285 | 372 |
| 286 } // namespace | 373 } // namespace |
| OLD | NEW |