Chromium Code Reviews| 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 21 matching lines...) Expand all Loading... | |
| 32 #include "core/html/HTMLShadowElement.h" | 32 #include "core/html/HTMLShadowElement.h" |
| 33 #include "core/html/HTMLSlotElement.h" | 33 #include "core/html/HTMLSlotElement.h" |
| 34 | 34 |
| 35 namespace blink { | 35 namespace blink { |
| 36 | 36 |
| 37 static inline ElementShadow* shadowFor(const Node& node) | 37 static inline ElementShadow* shadowFor(const Node& node) |
| 38 { | 38 { |
| 39 return node.isElementNode() ? toElement(node).shadow() : nullptr; | 39 return node.isElementNode() ? toElement(node).shadow() : nullptr; |
| 40 } | 40 } |
| 41 | 41 |
| 42 static inline bool canBeDistributedToInsertionPoint(const Node& node) | |
| 43 { | |
| 44 return node.isInV0ShadowTree() || node.isChildOfV0ShadowHost(); | |
| 45 } | |
| 46 | |
| 42 Node* ComposedTreeTraversal::traverseChild(const Node& node, TraversalDirection direction) | 47 Node* ComposedTreeTraversal::traverseChild(const Node& node, TraversalDirection direction) |
| 43 { | 48 { |
| 44 ElementShadow* shadow = shadowFor(node); | 49 ElementShadow* shadow = shadowFor(node); |
| 45 if (shadow) { | 50 if (shadow) { |
| 46 ShadowRoot& shadowRoot = shadow->youngestShadowRoot(); | 51 ShadowRoot& shadowRoot = shadow->youngestShadowRoot(); |
| 47 return resolveDistributionStartingAt(direction == TraversalDirectionForw ard ? shadowRoot.firstChild() : shadowRoot.lastChild(), direction); | 52 return resolveDistributionStartingAt(direction == TraversalDirectionForw ard ? shadowRoot.firstChild() : shadowRoot.lastChild(), direction); |
| 48 } | 53 } |
| 49 return resolveDistributionStartingAt(direction == TraversalDirectionForward ? node.firstChild() : node.lastChild(), direction); | 54 return resolveDistributionStartingAt(direction == TraversalDirectionForward ? node.firstChild() : node.lastChild(), direction); |
| 50 } | 55 } |
| 51 | 56 |
| 52 Node* ComposedTreeTraversal::resolveDistributionStartingAt(const Node* node, Tra versalDirection direction) | 57 Node* ComposedTreeTraversal::resolveDistributionStartingAt(const Node* node, Tra versalDirection direction) |
| 53 { | 58 { |
| 54 if (!node) | 59 if (!node) |
| 55 return nullptr; | 60 return nullptr; |
| 56 if (node->isInShadowTree() && node->containingShadowRoot()->isV1()) | 61 for (const Node* sibling = node; sibling; sibling = (direction == TraversalD irectionForward ? sibling->nextSibling() : sibling->previousSibling())) { |
| 57 return v1ResolveDistributionStartingAt(*node, direction); | 62 if (isHTMLSlotElement(*sibling)) { |
| 58 return v0ResolveDistributionStartingAt(*node, direction); | 63 const HTMLSlotElement& slot = toHTMLSlotElement(*sibling); |
| 64 if (Node* found = (direction == TraversalDirectionForward ? slot.fir stDistributedNode() : slot.lastDistributedNode())) | |
| 65 return found; | |
| 66 continue; | |
| 67 } | |
| 68 if (node->isInV0ShadowTree()) | |
| 69 return v0ResolveDistributionStartingAt(*sibling, direction); | |
| 70 return const_cast<Node*>(sibling); | |
| 71 } | |
| 72 return nullptr; | |
| 59 } | 73 } |
| 60 | 74 |
| 61 Node* ComposedTreeTraversal::v0ResolveDistributionStartingAt(const Node& node, T raversalDirection direction) | 75 Node* ComposedTreeTraversal::v0ResolveDistributionStartingAt(const Node& node, T raversalDirection direction) |
| 62 { | 76 { |
| 77 ASSERT(!isHTMLSlotElement(node)); | |
| 63 for (const Node* sibling = &node; sibling; sibling = (direction == Traversal DirectionForward ? sibling->nextSibling() : sibling->previousSibling())) { | 78 for (const Node* sibling = &node; sibling; sibling = (direction == Traversal DirectionForward ? sibling->nextSibling() : sibling->previousSibling())) { |
| 64 if (!isActiveInsertionPoint(*sibling)) | 79 if (!isActiveInsertionPoint(*sibling)) |
| 65 return const_cast<Node*>(sibling); | 80 return const_cast<Node*>(sibling); |
| 66 const InsertionPoint& insertionPoint = toInsertionPoint(*sibling); | 81 const InsertionPoint& insertionPoint = toInsertionPoint(*sibling); |
| 67 if (Node* found = (direction == TraversalDirectionForward ? insertionPoi nt.firstDistributedNode() : insertionPoint.lastDistributedNode())) | 82 if (Node* found = (direction == TraversalDirectionForward ? insertionPoi nt.firstDistributedNode() : insertionPoint.lastDistributedNode())) |
| 68 return found; | 83 return found; |
| 69 ASSERT(isHTMLShadowElement(insertionPoint) || (isHTMLContentElement(inse rtionPoint) && !insertionPoint.hasChildren())); | 84 ASSERT(isHTMLShadowElement(insertionPoint) || (isHTMLContentElement(inse rtionPoint) && !insertionPoint.hasChildren())); |
| 70 } | 85 } |
| 71 return nullptr; | 86 return nullptr; |
| 72 } | 87 } |
| 73 | 88 |
| 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) | 89 static HTMLSlotElement* finalDestinationSlotFor(const Node& node) |
| 87 { | 90 { |
| 88 HTMLSlotElement* slot = node.assignedSlot(); | 91 HTMLSlotElement* slot = node.assignedSlot(); |
| 89 if (!slot) | 92 if (!slot) |
| 90 return nullptr; | 93 return nullptr; |
| 91 for (HTMLSlotElement* next = slot->assignedSlot(); next; next = next->assign edSlot()) { | 94 for (HTMLSlotElement* next = slot->assignedSlot(); next; next = next->assign edSlot()) { |
| 92 slot = next; | 95 slot = next; |
| 93 } | 96 } |
| 94 return slot; | 97 return slot; |
| 95 } | 98 } |
| 96 | 99 |
| 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 | |
| 112 // TODO(hayato): This may return a wrong result for a node which is not in a | 100 // TODO(hayato): This may return a wrong result for a node which is not in a |
| 113 // document composed tree. See ComposedTreeTraversalTest's redistribution test for details. | 101 // document composed tree. See ComposedTreeTraversalTest's redistribution test for details. |
| 114 Node* ComposedTreeTraversal::v0TraverseSiblings(const Node& node, TraversalDirec tion direction) | 102 Node* ComposedTreeTraversal::traverseSiblings(const Node& node, TraversalDirecti on direction) |
| 115 { | 103 { |
| 116 if (!shadowWhereNodeCanBeDistributed(node)) | 104 if (node.isChildOfV1ShadowHost()) |
| 117 return traverseSiblingsOrShadowInsertionPointSiblings(node, direction); | 105 return traverseSiblingsForV1HostChild(node, direction); |
| 118 | 106 |
| 107 if (shadowWhereNodeCanBeDistributed(node)) | |
| 108 return traverseSiblingsForV0Distribution(node, direction); | |
| 109 | |
| 110 if (Node* found = resolveDistributionStartingAt(direction == TraversalDirect ionForward ? node.nextSibling() : node.previousSibling(), direction)) | |
| 111 return found; | |
| 112 | |
| 113 // For v0 older shadow tree | |
| 114 if (node.parentNode() && node.parentNode()->isShadowRoot()) { | |
|
kochi
2016/01/05 07:44:11
Can you add an assertion here (ASSERT(node.isInV0S
hayato
2016/01/06 05:49:09
No. This code is to support v1 shadow tree, but th
kochi
2016/01/06 06:21:34
Acknowledged.
| |
| 115 ShadowRoot* parentShadowRoot = toShadowRoot(node.parentNode()); | |
| 116 if (!parentShadowRoot->isYoungest()) { | |
| 117 HTMLShadowElement* assignedInsertionPoint = parentShadowRoot->shadow InsertionPointOfYoungerShadowRoot(); | |
| 118 ASSERT(assignedInsertionPoint); | |
| 119 return traverseSiblings(*assignedInsertionPoint, direction); | |
| 120 } | |
| 121 } | |
| 122 return nullptr; | |
| 123 } | |
| 124 | |
| 125 Node* ComposedTreeTraversal::traverseSiblingsForV1HostChild(const Node& node, Tr aversalDirection direction) | |
| 126 { | |
| 127 HTMLSlotElement* slot = finalDestinationSlotFor(node); | |
| 128 if (!slot) | |
| 129 return nullptr; | |
| 130 if (Node* siblingInDistributedNodes = (direction == TraversalDirectionForwar d ? slot->distributedNodeNextTo(node) : slot->distributedNodePreviousTo(node))) | |
| 131 return siblingInDistributedNodes; | |
| 132 return traverseSiblings(*slot, direction); | |
| 133 } | |
| 134 | |
| 135 Node* ComposedTreeTraversal::traverseSiblingsForV0Distribution(const Node& node, TraversalDirection direction) | |
| 136 { | |
| 119 const InsertionPoint* finalDestination = resolveReprojection(&node); | 137 const InsertionPoint* finalDestination = resolveReprojection(&node); |
| 120 if (!finalDestination) | 138 if (!finalDestination) |
| 121 return nullptr; | 139 return nullptr; |
| 122 if (Node* found = (direction == TraversalDirectionForward ? finalDestination ->distributedNodeNextTo(&node) : finalDestination->distributedNodePreviousTo(&no de))) | 140 if (Node* found = (direction == TraversalDirectionForward ? finalDestination ->distributedNodeNextTo(&node) : finalDestination->distributedNodePreviousTo(&no de))) |
| 123 return found; | 141 return found; |
| 124 return traverseSiblings(*finalDestination, direction); | 142 return traverseSiblings(*finalDestination, direction); |
| 125 } | |
| 126 | 143 |
| 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 | |
| 137 Node* ComposedTreeTraversal::traverseSiblingsOrShadowInsertionPointSiblings(cons t Node& node, TraversalDirection direction) | |
| 138 { | |
| 139 if (Node* found = resolveDistributionStartingAt(direction == TraversalDirect ionForward ? node.nextSibling() : node.previousSibling(), direction)) | |
| 140 return found; | |
| 141 | |
| 142 if (node.parentNode() && node.parentNode()->isShadowRoot()) { | |
| 143 ShadowRoot* parentShadowRoot = toShadowRoot(node.parentNode()); | |
| 144 if (!parentShadowRoot->isYoungest()) { | |
| 145 HTMLShadowElement* assignedInsertionPoint = parentShadowRoot->shadow InsertionPointOfYoungerShadowRoot(); | |
| 146 ASSERT(assignedInsertionPoint); | |
| 147 return traverseSiblingsOrShadowInsertionPointSiblings(*assignedInser tionPoint, direction); | |
| 148 } | |
| 149 } | |
| 150 return nullptr; | |
| 151 } | |
| 152 | |
| 153 static ElementShadow* parentElementShadow(const Node& node) | |
| 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 } | 144 } |
| 162 | 145 |
| 163 ContainerNode* ComposedTreeTraversal::traverseParent(const Node& node, ParentTra versalDetails* details) | 146 ContainerNode* ComposedTreeTraversal::traverseParent(const Node& node, ParentTra versalDetails* details) |
| 164 { | 147 { |
| 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. | 148 // 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. |
| 166 if (node.isPseudoElement()) | 149 if (node.isPseudoElement()) |
| 167 return node.parentOrShadowHostNode(); | 150 return node.parentOrShadowHostNode(); |
| 168 | 151 |
| 169 ElementShadow* shadow = parentElementShadow(node); | 152 if (node.isChildOfV1ShadowHost()) { |
| 170 if (shadow && shadow->isV1()) | 153 HTMLSlotElement* slot = finalDestinationSlotFor(node); |
| 171 return v1TraverseParent(node); | 154 if (!slot) |
| 172 if (shadowWhereNodeCanBeDistributed(node)) | 155 return nullptr; |
| 173 return v0TraverseParent(node, details); | 156 return traverseParent(*slot); |
| 157 } | |
| 158 | |
| 159 Element* parent = node.parentElement(); | |
| 160 if (parent && isHTMLSlotElement(parent)) { | |
| 161 HTMLSlotElement& slot = toHTMLSlotElement(*parent); | |
| 162 if (!slot.getAssignedNodes().isEmpty()) | |
| 163 return nullptr; | |
| 164 return traverseParent(slot, details); | |
| 165 } | |
| 166 | |
| 167 if (canBeDistributedToInsertionPoint(node)) | |
| 168 return traverseParentForV0(node, details); | |
| 169 | |
| 170 ASSERT(!shadowWhereNodeCanBeDistributed(node)); | |
| 174 return traverseParentOrHost(node); | 171 return traverseParentOrHost(node); |
| 175 } | 172 } |
| 176 | 173 |
| 177 ContainerNode* ComposedTreeTraversal::v1TraverseParent(const Node& node) | 174 ContainerNode* ComposedTreeTraversal::traverseParentForV0(const Node& node, Pare ntTraversalDetails* details) |
| 178 { | 175 { |
| 179 HTMLSlotElement* slot = finalDestinationSlotFor(node); | 176 if (shadowWhereNodeCanBeDistributed(node)) { |
| 180 if (!slot) | 177 if (const InsertionPoint* insertionPoint = resolveReprojection(&node)) { |
| 181 return nullptr; | 178 if (details) |
| 182 if (parentElementShadow(*slot)) { | 179 details->didTraverseInsertionPoint(insertionPoint); |
| 183 // The node is distributed to the |slot|, however, |slot|, which is a | 180 // The node is distributed. But the distribution was stopped at this insertion point. |
| 184 // child of a shadow host, is not assigned to any slots. | 181 if (shadowWhereNodeCanBeDistributed(*insertionPoint)) |
| 182 return nullptr; | |
| 183 return traverseParent(*insertionPoint); | |
| 184 } | |
| 185 return nullptr; | 185 return nullptr; |
| 186 } | 186 } |
| 187 return traverseParentOrHost(*slot); | 187 ContainerNode* parent = traverseParentOrHost(node); |
| 188 if (isActiveInsertionPoint(*parent)) | |
| 189 return nullptr; | |
| 190 return parent; | |
| 188 } | 191 } |
| 189 | 192 |
| 190 ContainerNode* ComposedTreeTraversal::v0TraverseParent(const Node& node, ParentT raversalDetails* details) | 193 ContainerNode* ComposedTreeTraversal::traverseParentOrHost(const Node& node) |
| 191 { | 194 { |
| 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; | |
| 201 } | |
| 202 | |
| 203 inline ContainerNode* ComposedTreeTraversal::traverseParentOrHost(const Node& no de) | |
| 204 { | |
| 205 // TODO(hayato): Support fallback contents of slots. The parent can be a slo t. | |
| 206 ContainerNode* parent = node.parentNode(); | 195 ContainerNode* parent = node.parentNode(); |
| 207 if (!parent) | 196 if (!parent) |
| 208 return nullptr; | 197 return nullptr; |
| 209 if (!parent->isShadowRoot()) | 198 if (!parent->isShadowRoot()) |
| 210 return parent; | 199 return parent; |
| 211 ShadowRoot* shadowRoot = toShadowRoot(parent); | 200 ShadowRoot* shadowRoot = toShadowRoot(parent); |
| 212 ASSERT(!shadowRoot->shadowInsertionPointOfYoungerShadowRoot()); | 201 ASSERT(!shadowRoot->shadowInsertionPointOfYoungerShadowRoot()); |
| 213 if (!shadowRoot->isYoungest()) | 202 if (!shadowRoot->isYoungest()) |
| 214 return nullptr; | 203 return nullptr; |
| 215 Element* host = shadowRoot->host(); | 204 return shadowRoot->host(); |
| 216 if (isActiveInsertionPoint(*host)) | |
| 217 return nullptr; | |
| 218 return host; | |
| 219 } | 205 } |
| 220 | 206 |
| 221 Node* ComposedTreeTraversal::childAt(const Node& node, unsigned index) | 207 Node* ComposedTreeTraversal::childAt(const Node& node, unsigned index) |
| 222 { | 208 { |
| 223 assertPrecondition(node); | 209 assertPrecondition(node); |
| 224 Node* child = traverseFirstChild(node); | 210 Node* child = traverseFirstChild(node); |
| 225 while (child && index--) | 211 while (child && index--) |
| 226 child = nextSibling(*child); | 212 child = nextSibling(*child); |
| 227 assertPostcondition(child); | 213 assertPostcondition(child); |
| 228 return child; | 214 return child; |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 364 Node& ComposedTreeTraversal::lastWithinOrSelf(const Node& node) | 350 Node& ComposedTreeTraversal::lastWithinOrSelf(const Node& node) |
| 365 { | 351 { |
| 366 assertPrecondition(node); | 352 assertPrecondition(node); |
| 367 Node* lastDescendant = lastWithin(node); | 353 Node* lastDescendant = lastWithin(node); |
| 368 Node& result = lastDescendant ? *lastDescendant : const_cast<Node&>(node); | 354 Node& result = lastDescendant ? *lastDescendant : const_cast<Node&>(node); |
| 369 assertPostcondition(&result); | 355 assertPostcondition(&result); |
| 370 return result; | 356 return result; |
| 371 } | 357 } |
| 372 | 358 |
| 373 } // namespace | 359 } // namespace |
| OLD | NEW |