Changeset 200464 in webkit
- Timestamp:
- May 5, 2016 11:33:17 AM (8 years ago)
- Location:
- trunk
- Files:
-
- 9 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r200461 r200464 1 2016-05-05 Ryosuke Niwa <rniwa@webkit.org> 2 3 event.target shouldn't be retargeted as the event bubbles into a slot 4 https://bugs.webkit.org/show_bug.cgi?id=157369 5 6 Reviewed by Antti Koivisto. 7 8 Updated test cases to expect the target to be not adjusted to a slot element when the event path 9 enters one as this didn't match the spec or the behavior of Google Chrome Canary. Both WebKit and 10 Chrome passes the test with this change. 11 12 * fast/shadow-dom/event-inside-slotted-node.html: 13 1 14 2016-05-04 Alex Christensen <achristensen@webkit.org> 2 15 -
trunk/LayoutTests/fast/shadow-dom/event-inside-slotted-node.html
r190214 r200464 81 81 assert_array_equals(log[0], [shadow.target, shadow.target], 'EventPath[0] must be the target'); 82 82 assert_array_equals(log[1], [shadow.targetParent, shadow.target], 'EventPath[1] must be the parent of the target'); 83 assert_array_equals(log[2], [shadow.slot, shadow. slot], 'EventPath[2] must be the slot');84 assert_array_equals(log[3], [shadow.slotParent, shadow. slot], 'EventPath[3] must be the parent of the slot');85 assert_array_equals(log[4], [shadow.root, shadow. slot], 'EventPath[4] must be the shadow root');83 assert_array_equals(log[2], [shadow.slot, shadow.target], 'EventPath[2] must be the slot'); 84 assert_array_equals(log[3], [shadow.slotParent, shadow.target], 'EventPath[3] must be the parent of the slot'); 85 assert_array_equals(log[4], [shadow.root, shadow.target], 'EventPath[4] must be the shadow root'); 86 86 assert_array_equals(log[5], [shadow.host, shadow.target], 'EventPath[5] must be the shadow host'); 87 87 … … 102 102 assert_array_equals(log[0], [shadow.target, shadow.target], 'EventPath[0] must be the target'); 103 103 assert_array_equals(log[1], [shadow.targetParent, shadow.target], 'EventPath[1] must be the parent of the target'); 104 assert_array_equals(log[2], [shadow.slot, shadow. slot], 'EventPath[2] must be the slot');105 assert_array_equals(log[3], [shadow.slotParent, shadow. slot], 'EventPath[3] must be the parent of the slot');106 assert_array_equals(log[4], [shadow.root, shadow. slot], 'EventPath[4] must be the shadow root');104 assert_array_equals(log[2], [shadow.slot, shadow.target], 'EventPath[2] must be the slot'); 105 assert_array_equals(log[3], [shadow.slotParent, shadow.target], 'EventPath[3] must be the parent of the slot'); 106 assert_array_equals(log[4], [shadow.root, shadow.target], 'EventPath[4] must be the shadow root'); 107 107 assert_array_equals(log[5], [shadow.host, shadow.target], 'EventPath[5] must be the shadow host'); 108 108 assert_array_equals(log[6], [document.body, shadow.target], 'EventPath[6] must be the body element'); … … 180 180 181 181 assert_array_equals(log[0], [shadow.target, shadow.target], 'EventPath[0] must be the target'); 182 assert_array_equals(log[1], [shadow.lowerSlot, shadow. lowerSlot], 'EventPath[1] must be the slot inside the lower shadow tree');183 assert_array_equals(log[2], [shadow.lowerSlot.parentNode, shadow. lowerSlot], 'EventPath[2] must be the parent of the slot inside the lower shadow tree');184 assert_array_equals(log[3], [shadow.innerSlot, shadow. innerSlot], 'EventPath[3] must be the slot inside the shadow tree inside the lower shadow tree');185 assert_array_equals(log[4], [shadow.innerSlot.parentNode, shadow. innerSlot], 'EventPath[4] must be the child of the inner shadow root');186 assert_array_equals(log[5], [shadow.innerShadow, shadow. innerSlot], 'EventPath[5] must be the inner shadow root');187 assert_array_equals(log[6], [shadow.innerShadow.host, shadow. lowerSlot], 'EventPath[6] must be the host of the inner shadow tree');188 assert_array_equals(log[7], [shadow.lowerShadow.firstChild, shadow. lowerSlot], 'EventPath[7] must be the parent of the inner shadow host');189 assert_array_equals(log[8], [shadow.lowerShadow, shadow. lowerSlot], 'EventPath[8] must be the lower shadow root');182 assert_array_equals(log[1], [shadow.lowerSlot, shadow.target], 'EventPath[1] must be the slot inside the lower shadow tree'); 183 assert_array_equals(log[2], [shadow.lowerSlot.parentNode, shadow.target], 'EventPath[2] must be the parent of the slot inside the lower shadow tree'); 184 assert_array_equals(log[3], [shadow.innerSlot, shadow.target], 'EventPath[3] must be the slot inside the shadow tree inside the lower shadow tree'); 185 assert_array_equals(log[4], [shadow.innerSlot.parentNode, shadow.target], 'EventPath[4] must be the child of the inner shadow root'); 186 assert_array_equals(log[5], [shadow.innerShadow, shadow.target], 'EventPath[5] must be the inner shadow root'); 187 assert_array_equals(log[6], [shadow.innerShadow.host, shadow.target], 'EventPath[6] must be the host of the inner shadow tree'); 188 assert_array_equals(log[7], [shadow.lowerShadow.firstChild, shadow.target], 'EventPath[7] must be the parent of the inner shadow host'); 189 assert_array_equals(log[8], [shadow.lowerShadow, shadow.target], 'EventPath[8] must be the lower shadow root'); 190 190 assert_array_equals(log[9], [shadow.lowerShadow.host, shadow.target], 'EventPath[9] must be the lower shadow host'); 191 191 assert_array_equals(log[10], [shadow.host.firstChild, shadow.target], 'EventPath[10] must be the parent of the grand parent of the target'); 192 assert_array_equals(log[11], [shadow.upperSlot, shadow. upperSlot], 'EventPath[11] must be the slot inside the upper shadow tree');193 assert_array_equals(log[12], [shadow.upperSlot.parentNode, shadow. upperSlot], 'EventPath[12] must be the parent of the slot inside the upper shadow tree');194 assert_array_equals(log[13], [shadow.upperShadow, shadow. upperSlot], 'EventPath[13] must be the upper shadow root');192 assert_array_equals(log[11], [shadow.upperSlot, shadow.target], 'EventPath[11] must be the slot inside the upper shadow tree'); 193 assert_array_equals(log[12], [shadow.upperSlot.parentNode, shadow.target], 'EventPath[12] must be the parent of the slot inside the upper shadow tree'); 194 assert_array_equals(log[13], [shadow.upperShadow, shadow.target], 'EventPath[13] must be the upper shadow root'); 195 195 assert_array_equals(log[14], [shadow.host, shadow.target], 'EventPath[14] must be the host'); 196 196 … … 216 216 + inner-host (3) -- (innerShadow; 2) 217 217 + span + i (1) 218 + slot + slot (innerSlot ; 0)218 + slot + slot (innerSlot, target; 0) 219 219 */ 220 220 … … 237 237 assert_array_equals(log[6], [shadow.lowerShadow.host, shadow.lowerShadow.host], 'EventPath[6] must be the lower (but outer) shadow root'); 238 238 assert_array_equals(log[7], [shadow.host.firstChild, shadow.lowerShadow.host], 'EventPath[7] must be the slot inside the upper shadow tree'); 239 assert_array_equals(log[8], [shadow.upperSlot, shadow. upperSlot], 'EventPath[8] must be the slot inside the upper shadow tree');240 assert_array_equals(log[9], [shadow.upperSlot.parentNode, shadow. upperSlot], 'EventPath[9] must be the parent of the slot inside the upper shadow tree');241 assert_array_equals(log[10], [shadow.upperShadow, shadow. upperSlot], 'EventPath[10] must be the upper shadow root');239 assert_array_equals(log[8], [shadow.upperSlot, shadow.lowerShadow.host], 'EventPath[8] must be the slot inside the upper shadow tree'); 240 assert_array_equals(log[9], [shadow.upperSlot.parentNode, shadow.lowerShadow.host], 'EventPath[9] must be the parent of the slot inside the upper shadow tree'); 241 assert_array_equals(log[10], [shadow.upperShadow, shadow.lowerShadow.host], 'EventPath[10] must be the upper shadow root'); 242 242 assert_array_equals(log[11], [shadow.upperShadow.host, shadow.lowerShadow.host], 'EventPath[11] must be the host'); 243 243 -
trunk/Source/WebCore/ChangeLog
r200463 r200464 1 2016-05-05 Ryosuke Niwa <rniwa@webkit.org> 2 3 event.target shouldn't be retargeted as the event bubbles into a slot 4 https://bugs.webkit.org/show_bug.cgi?id=157369 5 6 Reviewed by Antti Koivisto. 7 8 When an event bubbles up from an assigned node to its assigned slot, we shouldn't be adjusting 9 event.target to point to the slot. Since a shadow tree should have access to nodes outside 10 the shadow tree, event.target is accessible inside the shadow tree of such a slot. 11 12 New behavior matches the behavior of Google Chrome Canary as well as the shadow DOM specification: 13 http://w3c.github.io/webcomponents/spec/shadow/#dfn-retargeting-algorithm 14 15 Test: fast/shadow-dom/event-inside-slotted-node.html 16 17 * dom/Event.cpp: 18 (WebCore::Event::deepPath): 19 * dom/EventContext.h: 20 (WebCore::EventContext::isUnreachableNode): Use Node::isUnclosedNode instead of isReachable. 21 (WebCore::EventContext::isReachable): Deleted. 22 * dom/EventPath.cpp: 23 (WebCore::EventPath::EventPath): Don't set the target to the slot when entering a slot. Also moved 24 the code to adjust the target as we exit a shadow tree to the end of the outer loop for clarity. 25 (WebCore::isUnclosedNodeOf): Deleted. Renamed to Node::isUnclosedNode. 26 (WebCore::EventPath::setRelatedTarget): 27 (WebCore::EventPath::computePathUnclosedToTarget): Renamed from computePathDisclosedToTarget. 28 (WebCore::moveOutOfAllShadowRoots): Extracted from RelatedNodeRetargeter::RelatedNodeRetargeter. 29 (WebCore::RelatedNodeRetargeter::RelatedNodeRetargeter): Fixed a bug that we were exiting early 30 without setting m_hasDifferentTreeRoot true when target and relatedNode are disconnected from 31 a document. 32 (WebCore::RelatedNodeRetargeter::currentNode): 33 (WebCore::RelatedNodeRetargeter::checkConsistency): Updated to match the spec with one exception. 34 We don't use null as the adjusted related target when the (original) related target and the target 35 are in two distinct disconnected trees since such a behavior is not Web compatible. This spec bug is 36 tracked by https://github.com/w3c/webcomponents/issues/494 37 * dom/EventPath.h: 38 (WebCore::EventPath::eventTargetRespectingTargetRules): Returns Node* instead of EventTarget* since 39 we need a Node in RelatedNodeRetargeter::checkConsistency. 40 * dom/Node.cpp: 41 (WebCore::Node::isUnclosedNode): Moved from RelatedNodeRetargeter.cpp 42 * dom/Node.h: 43 1 44 2016-05-02 Sam Weinig <sam@webkit.org> 2 45 -
trunk/Source/WebCore/dom/Event.cpp
r198115 r200464 192 192 if (!m_eventPath) 193 193 return Vector<EventTarget*>(); 194 return m_eventPath->computePath DisclosedToTarget(*m_target);194 return m_eventPath->computePathUnclosedToTarget(*m_currentTarget); 195 195 } 196 196 -
trunk/Source/WebCore/dom/EventContext.h
r198483 r200464 58 58 #if !ASSERT_DISABLED 59 59 bool isUnreachableNode(EventTarget*); 60 bool isReachable(Node*) const;61 60 #endif 62 61 RefPtr<Node> m_node; … … 135 134 { 136 135 // FIXME: Checks also for SVG elements. 137 return target && target->toNode() && !target->toNode()->isSVGElement() && !isReachable(target->toNode()); 138 } 139 140 inline bool EventContext::isReachable(Node* target) const 141 { 142 ASSERT(target); 143 TreeScope& targetScope = target->treeScope(); 144 for (TreeScope* scope = &m_node->treeScope(); scope; scope = scope->parentTreeScope()) { 145 if (scope == &targetScope) 146 return true; 147 } 148 return false; 136 return target && target->toNode() && !target->toNode()->isSVGElement() && !m_node->isUnclosedNode(*target->toNode()); 149 137 } 150 138 #endif -
trunk/Source/WebCore/dom/EventPath.cpp
r198056 r200464 61 61 class RelatedNodeRetargeter { 62 62 public: 63 RelatedNodeRetargeter(Node& relatedNode, TreeScope& targetTreeScope);64 65 Node* currentNode( TreeScope& currentTreeScope);63 RelatedNodeRetargeter(Node& relatedNode, Node& target); 64 65 Node* currentNode(Node& currentTreeScope); 66 66 void moveToNewTreeScope(TreeScope* previousTreeScope, TreeScope& newTreeScope); 67 67 … … 72 72 73 73 #if ASSERT_DISABLED 74 void checkConsistency( TreeScope&) { }74 void checkConsistency(Node&) { } 75 75 #else 76 void checkConsistency( TreeScope& currentTreeScope);76 void checkConsistency(Node& currentTarget); 77 77 #endif 78 78 … … 87 87 : m_event(event) 88 88 { 89 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)90 Vector<EventTarget*, 16> targetStack;91 #endif92 93 89 bool isMouseOrFocusEvent = event.isMouseEvent() || event.isFocusEvent(); 94 90 #if ENABLE(TOUCH_EVENTS) 95 91 bool isTouchEvent = event.isTouchEvent(); 96 92 #endif 97 EventTarget* target = nullptr;98 99 93 Node* node = nodeOrHostIfPseudoElement(&originalTarget); 94 Node* target = eventTargetRespectingTargetRules(*node); 100 95 while (node) { 101 if (!target) 102 target = eventTargetRespectingTargetRules(*node); 103 ContainerNode* parent; 104 for (; node; node = parent) { 96 while (node) { 105 97 EventTarget* currentTarget = eventTargetRespectingTargetRules(*node); 106 98 … … 117 109 break; 118 110 119 parent = node->parentNode(); 120 111 ContainerNode* parent = node->parentNode(); 121 112 if (!parent) 122 113 return; … … 126 117 if (auto* assignedSlot = shadowRootOfParent->findAssignedSlot(*node)) { 127 118 // node is assigned to a slot. Continue dispatching the event at this slot. 128 targetStack.append(target);129 119 parent = assignedSlot; 130 target = assignedSlot;131 120 } 132 121 } … … 135 124 } 136 125 126 bool exitingShadowTreeOfTarget = &target->treeScope() == &node->treeScope(); 137 127 ShadowRoot& shadowRoot = downcast<ShadowRoot>(*node); 138 // At a shadow root. Continue dispatching the event at the shadow host.139 #if ENABLE(SHADOW_DOM) || ENABLE(DETAILS_ELEMENT)140 if (!targetStack.isEmpty()) {141 // Move target back to a descendant of the shadow host if the event did not originate in this shadow tree or its inner shadow trees.142 target = targetStack.last();143 targetStack.removeLast();144 ASSERT(shadowRoot.host()->contains(target->toNode()));145 } else146 #endif147 target = nullptr;148 149 128 if (!shouldEventCrossShadowBoundary(event, shadowRoot, originalTarget)) 150 129 return; 151 130 node = shadowRoot.host(); 131 if (exitingShadowTreeOfTarget) 132 target = eventTargetRespectingTargetRules(*node); 133 152 134 } 153 135 } … … 159 141 return; 160 142 161 RelatedNodeRetargeter retargeter(*relatedNode, downcast<MouseOrFocusEventContext>(*m_path[0]).node()->treeScope());143 RelatedNodeRetargeter retargeter(*relatedNode, *m_path[0]->node()); 162 144 163 145 bool originIsRelatedTarget = &origin == relatedNode; … … 169 151 auto& context = downcast<MouseOrFocusEventContext>(*m_path[contextIndex]); 170 152 171 TreeScope& currentTreeScope = context.node()->treeScope(); 153 Node& currentTarget = *context.node(); 154 TreeScope& currentTreeScope = currentTarget.treeScope(); 172 155 if (UNLIKELY(previousTreeScope && ¤tTreeScope != previousTreeScope)) 173 156 retargeter.moveToNewTreeScope(previousTreeScope, currentTreeScope); 174 157 175 Node* currentRelatedNode = retargeter.currentNode(currentT reeScope);158 Node* currentRelatedNode = retargeter.currentNode(currentTarget); 176 159 if (UNLIKELY(relatedTargetScoped && !originIsRelatedTarget && context.target() == currentRelatedNode)) { 177 160 m_path.shrink(contextIndex); … … 201 184 return; 202 185 203 RelatedNodeRetargeter retargeter(*targetNode, m_path[0]->node()->treeScope());186 RelatedNodeRetargeter retargeter(*targetNode, *m_path[0]->node()); 204 187 TreeScope* previousTreeScope = nullptr; 205 188 for (auto& context : m_path) { 206 TreeScope& currentTreeScope = context->node()->treeScope(); 189 Node& currentTarget = *context->node(); 190 TreeScope& currentTreeScope = currentTarget.treeScope(); 207 191 if (UNLIKELY(previousTreeScope && ¤tTreeScope != previousTreeScope)) 208 192 retargeter.moveToNewTreeScope(previousTreeScope, currentTreeScope); 209 193 210 Node* currentRelatedNode = retargeter.currentNode(currentT reeScope);194 Node* currentRelatedNode = retargeter.currentNode(currentTarget); 211 195 downcast<TouchEventContext>(*context).touchList(touchListType)->append(touch.cloneWithNewTarget(currentRelatedNode)); 212 196 … … 244 228 } 245 229 246 // http://w3c.github.io/webcomponents/spec/shadow/#dfn-unclosed-node 247 static bool isUnclosedNodeOf(const Node& a, const Node& b) 248 { 249 // Use Vector instead of HashSet since we expect the number of ancestor tree scopes to be small. 250 Vector<TreeScope*, 8> treeScopesOpenToB; 251 252 for (auto* scope = &b.treeScope(); scope; scope = scope->parentTreeScope()) 253 treeScopesOpenToB.append(scope); 254 255 for (auto* treeScopeThatCanAccessA = &a.treeScope(); treeScopeThatCanAccessA; treeScopeThatCanAccessA = treeScopeThatCanAccessA->parentTreeScope()) { 256 for (auto* openToB : treeScopesOpenToB) { 257 if (openToB == treeScopeThatCanAccessA) 258 return true; 259 } 260 auto& root = treeScopeThatCanAccessA->rootNode(); 261 if (is<ShadowRoot>(root) && downcast<ShadowRoot>(root).type() != ShadowRoot::Type::Open) 262 break; 263 } 264 265 return false; 266 } 267 268 Vector<EventTarget*> EventPath::computePathDisclosedToTarget(const EventTarget& target) const 230 Vector<EventTarget*> EventPath::computePathUnclosedToTarget(const EventTarget& target) const 269 231 { 270 232 Vector<EventTarget*> path; … … 275 237 for (auto& context : m_path) { 276 238 if (Node* nodeInPath = context->currentTarget()->toNode()) { 277 if ( isUnclosedNodeOf(*nodeInPath, *targetNode))239 if (targetNode->isUnclosedNode(*nodeInPath)) 278 240 path.append(context->currentTarget()); 279 241 } … … 283 245 } 284 246 285 RelatedNodeRetargeter::RelatedNodeRetargeter(Node& relatedNode, TreeScope& targetTreeScope) 247 static Node* moveOutOfAllShadowRoots(Node& startingNode) 248 { 249 Node* node = &startingNode; 250 while (node->isInShadowTree()) 251 node = downcast<ShadowRoot>(node->treeScope().rootNode()).host(); 252 return node; 253 } 254 255 RelatedNodeRetargeter::RelatedNodeRetargeter(Node& relatedNode, Node& target) 286 256 : m_relatedNode(relatedNode) 287 257 , m_retargetedRelatedNode(&relatedNode) 288 258 { 259 auto& targetTreeScope = target.treeScope(); 289 260 TreeScope* currentTreeScope = &m_relatedNode.treeScope(); 290 if (LIKELY(currentTreeScope == &targetTreeScope ))261 if (LIKELY(currentTreeScope == &targetTreeScope && target.inDocument() && m_relatedNode.inDocument())) 291 262 return; 292 263 … … 296 267 return; 297 268 } 298 if (relatedNode.inDocument() != target TreeScope.rootNode().inDocument()) {269 if (relatedNode.inDocument() != target.inDocument()) { 299 270 m_hasDifferentTreeRoot = true; 300 while (m_retargetedRelatedNode->isInShadowTree()) 301 m_retargetedRelatedNode = downcast<ShadowRoot>(m_retargetedRelatedNode->treeScope().rootNode()).host(); 271 m_retargetedRelatedNode = moveOutOfAllShadowRoots(relatedNode); 302 272 return; 303 273 } … … 321 291 } 322 292 293 bool lowestCommonAncestorIsDocumentScope = i + 1 == m_ancestorTreeScopes.size(); 294 if (lowestCommonAncestorIsDocumentScope && !relatedNode.inDocument() && !target.inDocument()) { 295 Node& targetAncestorInDocumentScope = i ? *downcast<ShadowRoot>(m_ancestorTreeScopes[i - 1]->rootNode()).shadowHost() : target; 296 Node& relatedNodeAncestorInDocumentScope = j ? *downcast<ShadowRoot>(targetTreeScopeAncestors[j - 1]->rootNode()).shadowHost() : relatedNode; 297 if (targetAncestorInDocumentScope.rootNode() != relatedNodeAncestorInDocumentScope.rootNode()) { 298 m_hasDifferentTreeRoot = true; 299 m_retargetedRelatedNode = moveOutOfAllShadowRoots(relatedNode); 300 return; 301 } 302 } 303 323 304 m_lowestCommonAncestorIndex = i; 324 305 m_retargetedRelatedNode = nodeInLowestCommonAncestor(); 325 306 } 326 307 327 inline Node* RelatedNodeRetargeter::currentNode( TreeScope& currentTreeScope)328 { 329 checkConsistency(currentT reeScope);308 inline Node* RelatedNodeRetargeter::currentNode(Node& currentTarget) 309 { 310 checkConsistency(currentTarget); 330 311 return m_retargetedRelatedNode; 331 312 } … … 382 363 383 364 #if !ASSERT_DISABLED 384 void RelatedNodeRetargeter::checkConsistency(TreeScope& currentTreeScope) 385 { 386 for (auto* relatedNodeScope = &m_relatedNode.treeScope(); relatedNodeScope; relatedNodeScope = relatedNodeScope->parentTreeScope()) { 387 for (auto* targetScope = ¤tTreeScope; targetScope; targetScope = targetScope->parentTreeScope()) { 388 if (targetScope == relatedNodeScope) { 389 ASSERT(&m_retargetedRelatedNode->treeScope() == relatedNodeScope); 390 return; 391 } 392 } 393 } 394 ASSERT(!m_retargetedRelatedNode); 395 } 396 #endif 397 398 } 365 void RelatedNodeRetargeter::checkConsistency(Node& currentTarget) 366 { 367 ASSERT(!m_retargetedRelatedNode || currentTarget.isUnclosedNode(*m_retargetedRelatedNode)); 368 369 // http://w3c.github.io/webcomponents/spec/shadow/#dfn-retargeting-algorithm 370 Node& base = currentTarget; 371 for (Node* targetAncestor = &m_relatedNode; targetAncestor; targetAncestor = targetAncestor->parentOrShadowHostNode()) { 372 if (targetAncestor->rootNode()->containsIncludingShadowDOM(&base)) { 373 ASSERT(m_retargetedRelatedNode == targetAncestor); 374 return; 375 } 376 } 377 ASSERT(!m_retargetedRelatedNode || m_hasDifferentTreeRoot); 378 } 379 #endif 380 381 } -
trunk/Source/WebCore/dom/EventPath.h
r198056 r200464 49 49 EventContext* lastContextIfExists() { return m_path.isEmpty() ? nullptr : m_path.last().get(); } 50 50 51 Vector<EventTarget*> computePath DisclosedToTarget(const EventTarget&) const;51 Vector<EventTarget*> computePathUnclosedToTarget(const EventTarget&) const; 52 52 53 static EventTarget* eventTargetRespectingTargetRules(Node& referenceNode)53 static Node* eventTargetRespectingTargetRules(Node& referenceNode) 54 54 { 55 55 if (is<PseudoElement>(referenceNode)) -
trunk/Source/WebCore/dom/Node.cpp
r200414 r200464 1118 1118 } 1119 1119 1120 // http://w3c.github.io/webcomponents/spec/shadow/#dfn-unclosed-node 1121 bool Node::isUnclosedNode(const Node& otherNode) const 1122 { 1123 // Use Vector instead of HashSet since we expect the number of ancestor tree scopes to be small. 1124 Vector<TreeScope*, 8> ancestorScopesOfThisNode; 1125 1126 for (auto* scope = &treeScope(); scope; scope = scope->parentTreeScope()) 1127 ancestorScopesOfThisNode.append(scope); 1128 1129 for (auto* treeScopeThatCanAccessOtherNode = &otherNode.treeScope(); treeScopeThatCanAccessOtherNode; treeScopeThatCanAccessOtherNode = treeScopeThatCanAccessOtherNode->parentTreeScope()) { 1130 for (auto* scope : ancestorScopesOfThisNode) { 1131 if (scope == treeScopeThatCanAccessOtherNode) 1132 return true; // treeScopeThatCanAccessOtherNode is a shadow-including inclusive ancestor of this node. 1133 } 1134 auto& root = treeScopeThatCanAccessOtherNode->rootNode(); 1135 if (is<ShadowRoot>(root) && downcast<ShadowRoot>(root).type() != ShadowRoot::Type::Open) 1136 break; 1137 } 1138 1139 return false; 1140 } 1141 1120 1142 #if ENABLE(SHADOW_DOM) 1121 1143 HTMLSlotElement* Node::assignedSlot() const -
trunk/Source/WebCore/dom/Node.h
r200414 r200464 260 260 ShadowRoot* containingShadowRoot() const; 261 261 ShadowRoot* shadowRoot() const; 262 bool isUnclosedNode(const Node&) const; 262 263 263 264 #if ENABLE(SHADOW_DOM)
Note: See TracChangeset
for help on using the changeset viewer.