1/* 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 4 * (C) 2001 Dirk Mueller (mueller@kde.org) 5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013 Apple Inc. All rights reserved. 6 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 7 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) 8 * Copyright (C) 2010, 2011, 2012, 2013 Google Inc. All rights reserved. 9 * 10 * This library is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Library General Public 12 * License as published by the Free Software Foundation; either 13 * version 2 of the License, or (at your option) any later version. 14 * 15 * This library is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Library General Public License for more details. 19 * 20 * You should have received a copy of the GNU Library General Public License 21 * along with this library; see the file COPYING.LIB. If not, write to 22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 23 * Boston, MA 02110-1301, USA. 24 */ 25 26#include "config.h" 27#include "EventDispatcher.h" 28 29#include "EventContext.h" 30#include "FocusEvent.h" 31#include "FrameView.h" 32#include "HTMLInputElement.h" 33#include "HTMLMediaElement.h" 34#include "InsertionPoint.h" 35#include "InspectorInstrumentation.h" 36#include "MouseEvent.h" 37#include "PseudoElement.h" 38#include "ScopedEventQueue.h" 39#include "ShadowRoot.h" 40#include "SVGElementInstance.h" 41#include "SVGNames.h" 42#include "SVGUseElement.h" 43#include "TouchEvent.h" 44 45namespace WebCore { 46 47class WindowEventContext { 48public: 49 WindowEventContext(PassRefPtr<Node>, const EventContext*); 50 51 DOMWindow* window() const { return m_window.get(); } 52 EventTarget* target() const { return m_target.get(); } 53 bool handleLocalEvents(Event&); 54 55private: 56 RefPtr<DOMWindow> m_window; 57 RefPtr<EventTarget> m_target; 58}; 59 60WindowEventContext::WindowEventContext(PassRefPtr<Node> node, const EventContext* topEventContext) 61{ 62 Node* topLevelContainer = topEventContext ? topEventContext->node() : node.get(); 63 if (!topLevelContainer->isDocumentNode()) 64 return; 65 66 m_window = toDocument(topLevelContainer)->domWindow(); 67 m_target = topEventContext ? topEventContext->target() : node.get(); 68} 69 70bool WindowEventContext::handleLocalEvents(Event& event) 71{ 72 if (!m_window) 73 return false; 74 75 event.setTarget(m_target.get()); 76 event.setCurrentTarget(m_window.get()); 77 m_window->fireEventListeners(&event); 78 return true; 79} 80 81class EventPath { 82public: 83 EventPath(Node& origin, Event&); 84 85 bool isEmpty() const { return m_path.isEmpty(); } 86 size_t size() const { return m_path.size(); } 87 const EventContext& contextAt(size_t i) const { return *m_path[i]; } 88 EventContext& contextAt(size_t i) { return *m_path[i]; } 89 90#if ENABLE(TOUCH_EVENTS) 91 bool updateTouchLists(const TouchEvent&); 92#endif 93 void setRelatedTarget(Node& origin, EventTarget&); 94 95 bool hasEventListeners(const AtomicString& eventType) const; 96 97 EventContext* lastContextIfExists() { return m_path.isEmpty() ? 0 : m_path.last().get(); } 98 99private: 100#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS) 101 void updateTouchListsInEventPath(const TouchList*, TouchEventContext::TouchListType); 102#endif 103 104 Vector<std::unique_ptr<EventContext>, 32> m_path; 105}; 106 107class EventRelatedNodeResolver { 108public: 109 EventRelatedNodeResolver(Node& relatedNode) 110 : m_relatedNode(relatedNode) 111 , m_relatedNodeTreeScope(relatedNode.treeScope()) 112 , m_relatedNodeInCurrentTreeScope(nullptr) 113 , m_currentTreeScope(nullptr) 114#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS) 115 , m_touch(0) 116 , m_touchListType(TouchEventContext::NotTouchList) 117#endif 118 { 119 } 120 121#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS) 122 EventRelatedNodeResolver(Touch& touch, TouchEventContext::TouchListType touchListType) 123 : m_relatedNode(*touch.target()->toNode()) 124 , m_relatedNodeTreeScope(m_relatedNode.treeScope()) 125 , m_relatedNodeInCurrentTreeScope(nullptr) 126 , m_currentTreeScope(nullptr) 127 , m_touch(&touch) 128 , m_touchListType(touchListType) 129 { 130 ASSERT(touch.target()->toNode()); 131 } 132#endif 133 134#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS) 135 Touch* touch() const { return m_touch; } 136 TouchEventContext::TouchListType touchListType() const { return m_touchListType; } 137#endif 138 139 Node* moveToParentOrShadowHost(Node& newTarget) 140 { 141 TreeScope& newTreeScope = newTarget.treeScope(); 142 if (&newTreeScope == m_currentTreeScope) 143 return m_relatedNodeInCurrentTreeScope; 144 145 if (m_currentTreeScope) { 146 ASSERT(m_currentTreeScope->rootNode().isShadowRoot()); 147 ASSERT(&newTarget == toShadowRoot(m_currentTreeScope->rootNode()).hostElement()); 148 ASSERT(m_currentTreeScope->parentTreeScope() == &newTreeScope); 149 } 150 151 if (&newTreeScope == &m_relatedNodeTreeScope) 152 m_relatedNodeInCurrentTreeScope = &m_relatedNode; 153 else if (m_relatedNodeInCurrentTreeScope) { 154 ASSERT(m_currentTreeScope); 155 m_relatedNodeInCurrentTreeScope = &newTarget; 156 } else { 157 if (!m_currentTreeScope) { 158 TreeScope* newTreeScopeAncestor = &newTreeScope; 159 do { 160 m_relatedNodeInCurrentTreeScope = findHostOfTreeScopeInTargetTreeScope(m_relatedNodeTreeScope, *newTreeScopeAncestor); 161 newTreeScopeAncestor = newTreeScopeAncestor->parentTreeScope(); 162 if (newTreeScopeAncestor == &m_relatedNodeTreeScope) { 163 m_relatedNodeInCurrentTreeScope = &m_relatedNode; 164 break; 165 } 166 } while (newTreeScopeAncestor && !m_relatedNodeInCurrentTreeScope); 167 } 168 ASSERT(m_relatedNodeInCurrentTreeScope || findHostOfTreeScopeInTargetTreeScope(newTreeScope, m_relatedNodeTreeScope) 169 || &newTreeScope.documentScope() != &m_relatedNodeTreeScope.documentScope()); 170 } 171 172 m_currentTreeScope = &newTreeScope; 173 174 return m_relatedNodeInCurrentTreeScope; 175 } 176 177 static Node* findHostOfTreeScopeInTargetTreeScope(const TreeScope& startingTreeScope, const TreeScope& targetScope) 178 { 179 ASSERT(&targetScope != &startingTreeScope); 180 Node* previousHost = nullptr; 181 for (const TreeScope* scope = &startingTreeScope; scope; scope = scope->parentTreeScope()) { 182 if (scope == &targetScope) { 183 ASSERT(previousHost); 184 ASSERT_WITH_SECURITY_IMPLICATION(&previousHost->treeScope() == &targetScope); 185 return previousHost; 186 } 187 if (scope->rootNode().isShadowRoot()) 188 previousHost = toShadowRoot(scope->rootNode()).hostElement(); 189 else 190 ASSERT_WITH_SECURITY_IMPLICATION(!scope->parentTreeScope()); 191 } 192 return nullptr; 193 } 194 195private: 196 Node& m_relatedNode; 197 const TreeScope& m_relatedNodeTreeScope; 198 Node* m_relatedNodeInCurrentTreeScope; 199 TreeScope* m_currentTreeScope; 200#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS) 201 Touch* m_touch; 202 TouchEventContext::TouchListType m_touchListType; 203#endif 204}; 205 206inline EventTarget& eventTargetRespectingTargetRules(Node& referenceNode) 207{ 208 if (referenceNode.isPseudoElement()) { 209 EventTarget* hostElement = toPseudoElement(referenceNode).hostElement(); 210 ASSERT(hostElement); 211 return *hostElement; 212 } 213 214 if (!referenceNode.isSVGElement() || !referenceNode.isInShadowTree()) 215 return referenceNode; 216 217 // Spec: The event handling for the non-exposed tree works as if the referenced element had been textually included 218 // as a deeply cloned child of the 'use' element, except that events are dispatched to the SVGElementInstance objects 219 auto& rootNode = referenceNode.treeScope().rootNode(); 220 Element* shadowHostElement = rootNode.isShadowRoot() ? toShadowRoot(rootNode).hostElement() : nullptr; 221 // At this time, SVG nodes are not supported in non-<use> shadow trees. 222 if (!shadowHostElement || !shadowHostElement->hasTagName(SVGNames::useTag)) 223 return referenceNode; 224 SVGUseElement* useElement = toSVGUseElement(shadowHostElement); 225 if (SVGElementInstance* instance = useElement->instanceForShadowTreeElement(&referenceNode)) 226 return *instance; 227 228 return referenceNode; 229} 230 231void EventDispatcher::dispatchScopedEvent(Node& node, PassRefPtr<Event> event) 232{ 233 // We need to set the target here because it can go away by the time we actually fire the event. 234 event->setTarget(&eventTargetRespectingTargetRules(node)); 235 ScopedEventQueue::instance().enqueueEvent(event); 236} 237 238void EventDispatcher::dispatchSimulatedClick(Element* element, Event* underlyingEvent, SimulatedClickMouseEventOptions mouseEventOptions, SimulatedClickVisualOptions visualOptions) 239{ 240 if (element->isDisabledFormControl()) 241 return; 242 243 DEPRECATED_DEFINE_STATIC_LOCAL(HashSet<Element*>, elementsDispatchingSimulatedClicks, ()); 244 if (!elementsDispatchingSimulatedClicks.add(element).isNewEntry) 245 return; 246 247 if (mouseEventOptions == SendMouseOverUpDownEvents) 248 dispatchEvent(element, SimulatedMouseEvent::create(eventNames().mouseoverEvent, element->document().defaultView(), underlyingEvent, element)); 249 250 if (mouseEventOptions != SendNoEvents) 251 dispatchEvent(element, SimulatedMouseEvent::create(eventNames().mousedownEvent, element->document().defaultView(), underlyingEvent, element)); 252 element->setActive(true, visualOptions == ShowPressedLook); 253 if (mouseEventOptions != SendNoEvents) 254 dispatchEvent(element, SimulatedMouseEvent::create(eventNames().mouseupEvent, element->document().defaultView(), underlyingEvent, element)); 255 element->setActive(false); 256 257 // always send click 258 dispatchEvent(element, SimulatedMouseEvent::create(eventNames().clickEvent, element->document().defaultView(), underlyingEvent, element)); 259 260 elementsDispatchingSimulatedClicks.remove(element); 261} 262 263static void callDefaultEventHandlersInTheBubblingOrder(Event& event, const EventPath& path) 264{ 265 if (path.isEmpty()) 266 return; 267 268 // Non-bubbling events call only one default event handler, the one for the target. 269 path.contextAt(0).node()->defaultEventHandler(&event); 270 ASSERT(!event.defaultPrevented()); 271 272 if (event.defaultHandled() || !event.bubbles()) 273 return; 274 275 size_t size = path.size(); 276 for (size_t i = 1; i < size; ++i) { 277 path.contextAt(i).node()->defaultEventHandler(&event); 278 ASSERT(!event.defaultPrevented()); 279 if (event.defaultHandled()) 280 return; 281 } 282} 283 284static void dispatchEventInDOM(Event& event, const EventPath& path, WindowEventContext& windowEventContext) 285{ 286 // Trigger capturing event handlers, starting at the top and working our way down. 287 event.setEventPhase(Event::CAPTURING_PHASE); 288 289 // We don't dispatch load events to the window. This quirk was originally 290 // added because Mozilla doesn't propagate load events to the window object. 291 bool shouldFireEventAtWindow = event.type() != eventNames().loadEvent; 292 if (shouldFireEventAtWindow && windowEventContext.handleLocalEvents(event) && event.propagationStopped()) 293 return; 294 295 for (size_t i = path.size() - 1; i > 0; --i) { 296 const EventContext& eventContext = path.contextAt(i); 297 if (eventContext.currentTargetSameAsTarget()) 298 continue; 299 eventContext.handleLocalEvents(event); 300 if (event.propagationStopped()) 301 return; 302 } 303 304 event.setEventPhase(Event::AT_TARGET); 305 path.contextAt(0).handleLocalEvents(event); 306 if (event.propagationStopped()) 307 return; 308 309 // Trigger bubbling event handlers, starting at the bottom and working our way up. 310 size_t size = path.size(); 311 for (size_t i = 1; i < size; ++i) { 312 const EventContext& eventContext = path.contextAt(i); 313 if (eventContext.currentTargetSameAsTarget()) 314 event.setEventPhase(Event::AT_TARGET); 315 else if (event.bubbles() && !event.cancelBubble()) 316 event.setEventPhase(Event::BUBBLING_PHASE); 317 else 318 continue; 319 eventContext.handleLocalEvents(event); 320 if (event.propagationStopped()) 321 return; 322 } 323 if (event.bubbles() && !event.cancelBubble()) { 324 event.setEventPhase(Event::BUBBLING_PHASE); 325 if (shouldFireEventAtWindow) 326 windowEventContext.handleLocalEvents(event); 327 } 328} 329 330bool EventDispatcher::dispatchEvent(Node* origin, PassRefPtr<Event> prpEvent) 331{ 332 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden()); 333 if (!prpEvent) 334 return true; 335 336 ASSERT(origin); 337 RefPtr<Node> node(origin); 338 RefPtr<Event> event(prpEvent); 339 RefPtr<FrameView> view = node->document().view(); 340 EventPath eventPath(*node, *event); 341 342 if (EventTarget* relatedTarget = event->relatedTarget()) 343 eventPath.setRelatedTarget(*node, *relatedTarget); 344#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS) 345 if (event->isTouchEvent()) { 346 if (!eventPath.updateTouchLists(*toTouchEvent(event.get()))) 347 return true; 348 } 349#endif 350 351 ChildNodesLazySnapshot::takeChildNodesLazySnapshot(); 352 353 event->setTarget(&eventTargetRespectingTargetRules(*node)); 354 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden()); 355 ASSERT(event->target()); 356 WindowEventContext windowEventContext(node.get(), eventPath.lastContextIfExists()); 357 358 InputElementClickState clickHandlingState; 359 if (isHTMLInputElement(node.get())) 360 toHTMLInputElement(*node).willDispatchEvent(*event, clickHandlingState); 361 362 if (!event->propagationStopped() && !eventPath.isEmpty()) 363 dispatchEventInDOM(*event, eventPath, windowEventContext); 364 365 event->setTarget(&eventTargetRespectingTargetRules(*node)); 366 event->setCurrentTarget(0); 367 event->setEventPhase(0); 368 369 if (clickHandlingState.stateful) 370 toHTMLInputElement(*node).didDispatchClickEvent(*event, clickHandlingState); 371 372 // Call default event handlers. While the DOM does have a concept of preventing 373 // default handling, the detail of which handlers are called is an internal 374 // implementation detail and not part of the DOM. 375 if (!event->defaultPrevented() && !event->defaultHandled()) 376 callDefaultEventHandlersInTheBubblingOrder(*event, eventPath); 377 378 // Ensure that after event dispatch, the event's target object is the 379 // outermost shadow DOM boundary. 380 event->setTarget(windowEventContext.target()); 381 event->setCurrentTarget(0); 382 383 return !event->defaultPrevented(); 384} 385 386static inline bool shouldEventCrossShadowBoundary(Event& event, ShadowRoot& shadowRoot, EventTarget& target) 387{ 388 Node* targetNode = target.toNode(); 389#if ENABLE(FULLSCREEN_API) && ENABLE(VIDEO) 390 // Video-only full screen is a mode where we use the shadow DOM as an implementation 391 // detail that should not be detectable by the web content. 392 if (targetNode) { 393 if (Element* element = targetNode->document().webkitCurrentFullScreenElement()) { 394 // FIXME: We assume that if the full screen element is a media element that it's 395 // the video-only full screen. Both here and elsewhere. But that is probably wrong. 396 if (element->isMediaElement() && shadowRoot.hostElement() == element) 397 return false; 398 } 399 } 400#endif 401 402 // WebKit never allowed selectstart event to cross the the shadow DOM boundary. 403 // Changing this breaks existing sites. 404 // See https://bugs.webkit.org/show_bug.cgi?id=52195 for details. 405 const AtomicString& eventType = event.type(); 406 bool targetIsInShadowRoot = targetNode && &targetNode->treeScope().rootNode() == &shadowRoot; 407 return !targetIsInShadowRoot 408 || !(eventType == eventNames().abortEvent 409 || eventType == eventNames().changeEvent 410 || eventType == eventNames().errorEvent 411 || eventType == eventNames().loadEvent 412 || eventType == eventNames().resetEvent 413 || eventType == eventNames().resizeEvent 414 || eventType == eventNames().scrollEvent 415 || eventType == eventNames().selectEvent 416 || eventType == eventNames().selectstartEvent); 417} 418 419static Node* nodeOrHostIfPseudoElement(Node* node) 420{ 421 return node->isPseudoElement() ? toPseudoElement(node)->hostElement() : node; 422} 423 424EventPath::EventPath(Node& targetNode, Event& event) 425{ 426 bool inDocument = targetNode.inDocument(); 427 bool isSVGElement = targetNode.isSVGElement(); 428 bool isMouseOrFocusEvent = event.isMouseEvent() || event.isFocusEvent(); 429#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS) 430 bool isTouchEvent = event.isTouchEvent(); 431#endif 432 EventTarget* target = 0; 433 434 Node* node = nodeOrHostIfPseudoElement(&targetNode); 435 while (node) { 436 if (!target || !isSVGElement) // FIXME: This code doesn't make sense once we've climbed out of the SVG subtree in a HTML document. 437 target = &eventTargetRespectingTargetRules(*node); 438 for (; node; node = node->parentNode()) { 439 EventTarget& currentTarget = eventTargetRespectingTargetRules(*node); 440 if (isMouseOrFocusEvent) 441 m_path.append(std::make_unique<MouseOrFocusEventContext>(node, ¤tTarget, target)); 442#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS) 443 else if (isTouchEvent) 444 m_path.append(std::make_unique<TouchEventContext>(node, ¤tTarget, target)); 445#endif 446 else 447 m_path.append(std::make_unique<EventContext>(node, ¤tTarget, target)); 448 if (!inDocument) 449 return; 450 if (node->isShadowRoot()) 451 break; 452 } 453 if (!node || !shouldEventCrossShadowBoundary(event, *toShadowRoot(node), *target)) 454 return; 455 node = toShadowRoot(node)->hostElement(); 456 } 457} 458 459#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS) 460static void addRelatedNodeResolversForTouchList(Vector<EventRelatedNodeResolver, 16>& touchTargetResolvers, TouchList* touchList, TouchEventContext::TouchListType type) 461{ 462 const size_t touchListSize = touchList->length(); 463 for (size_t i = 0; i < touchListSize; ++i) 464 touchTargetResolvers.append(EventRelatedNodeResolver(*touchList->item(i), type)); 465} 466 467bool EventPath::updateTouchLists(const TouchEvent& touchEvent) 468{ 469 if (!touchEvent.touches() || !touchEvent.targetTouches() || !touchEvent.changedTouches()) 470 return false; 471 472 Vector<EventRelatedNodeResolver, 16> touchTargetResolvers; 473 const size_t touchNodeCount = touchEvent.touches()->length() + touchEvent.targetTouches()->length() + touchEvent.changedTouches()->length(); 474 touchTargetResolvers.reserveInitialCapacity(touchNodeCount); 475 476 addRelatedNodeResolversForTouchList(touchTargetResolvers, touchEvent.touches(), TouchEventContext::Touches); 477 addRelatedNodeResolversForTouchList(touchTargetResolvers, touchEvent.targetTouches(), TouchEventContext::TargetTouches); 478 addRelatedNodeResolversForTouchList(touchTargetResolvers, touchEvent.changedTouches(), TouchEventContext::ChangedTouches); 479 480 ASSERT(touchTargetResolvers.size() == touchNodeCount); 481 size_t eventPathSize = m_path.size(); 482 for (size_t i = 0; i < eventPathSize; ++i) { 483 TouchEventContext& context = toTouchEventContext(*m_path[i]); 484 Node& nodeToMoveTo = *context.node(); 485 for (size_t resolverIndex = 0; resolverIndex < touchNodeCount; ++resolverIndex) { 486 EventRelatedNodeResolver& currentResolver = touchTargetResolvers[resolverIndex]; 487 Node* nodeInCurrentTreeScope = currentResolver.moveToParentOrShadowHost(nodeToMoveTo); 488 ASSERT(currentResolver.touch()); 489 context.touchList(currentResolver.touchListType())->append(currentResolver.touch()->cloneWithNewTarget(nodeInCurrentTreeScope)); 490 } 491 } 492 return true; 493} 494#endif 495 496void EventPath::setRelatedTarget(Node& origin, EventTarget& relatedTarget) 497{ 498 Node* relatedNode = relatedTarget.toNode(); 499 if (!relatedNode) 500 return; 501 502 EventRelatedNodeResolver resolver(*relatedNode); 503 504 bool originIsRelatedTarget = &origin == relatedNode; 505 Node& rootNodeInOriginTreeScope = origin.treeScope().rootNode(); 506 507 size_t eventPathSize = m_path.size(); 508 size_t i = 0; 509 while (i < eventPathSize) { 510 Node* contextNode = m_path[i]->node(); 511 Node* currentRelatedNode = resolver.moveToParentOrShadowHost(*contextNode); 512 if (!originIsRelatedTarget && m_path[i]->target() == currentRelatedNode) 513 break; 514 toMouseOrFocusEventContext(*m_path[i]).setRelatedTarget(currentRelatedNode); 515 i++; 516 if (originIsRelatedTarget && &rootNodeInOriginTreeScope == contextNode) 517 break; 518 } 519 m_path.shrink(i); 520} 521 522bool EventPath::hasEventListeners(const AtomicString& eventType) const 523{ 524 for (size_t i = 0; i < m_path.size(); i++) { 525 if (m_path[i]->node()->hasEventListeners(eventType)) 526 return true; 527 } 528 529 return false; 530} 531 532} 533