1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2001 Dirk Mueller (mueller (at) kde.org) 5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 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) 2011 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 "Event.h" 30 #include "EventContext.h" 31 #include "EventTarget.h" 32 #include "FrameView.h" 33 #include "InspectorInstrumentation.h" 34 #include "MouseEvent.h" 35 #include "Node.h" 36 #include "ScopedEventQueue.h" 37 38 #if ENABLE(SVG) 39 #include "SVGElementInstance.h" 40 #include "SVGNames.h" 41 #include "SVGUseElement.h" 42 #endif 43 44 #include "UIEvent.h" 45 #include "UIEventWithKeyState.h" 46 #include "WindowEventContext.h" 47 48 #include <wtf/RefPtr.h> 49 50 namespace WebCore { 51 52 static HashSet<Node*>* gNodesDispatchingSimulatedClicks = 0; 53 54 bool EventDispatcher::dispatchEvent(Node* node, const EventDispatchMediator& mediator) 55 { 56 ASSERT(!eventDispatchForbidden()); 57 58 EventDispatcher dispatcher(node); 59 return mediator.dispatchEvent(&dispatcher); 60 } 61 62 static EventTarget* findElementInstance(Node* referenceNode) 63 { 64 #if ENABLE(SVG) 65 // Spec: The event handling for the non-exposed tree works as if the referenced element had been textually included 66 // as a deeply cloned child of the 'use' element, except that events are dispatched to the SVGElementInstance objects 67 for (Node* n = referenceNode; n; n = n->parentNode()) { 68 if (!n->isSVGShadowRoot() || !n->isSVGElement()) 69 continue; 70 71 Element* shadowTreeParentElement = n->svgShadowHost(); 72 ASSERT(shadowTreeParentElement->hasTagName(SVGNames::useTag)); 73 74 if (SVGElementInstance* instance = static_cast<SVGUseElement*>(shadowTreeParentElement)->instanceForShadowTreeElement(referenceNode)) 75 return instance; 76 } 77 #else 78 // SVG elements with SVG disabled should not be possible. 79 ASSERT_NOT_REACHED(); 80 #endif 81 82 return referenceNode; 83 } 84 85 inline static EventTarget* eventTargetRespectingSVGTargetRules(Node* referenceNode) 86 { 87 ASSERT(referenceNode); 88 89 return referenceNode->isSVGElement() ? findElementInstance(referenceNode) : referenceNode; 90 } 91 92 void EventDispatcher::dispatchScopedEvent(Node* node, PassRefPtr<Event> event) 93 { 94 // We need to set the target here because it can go away by the time we actually fire the event. 95 event->setTarget(eventTargetRespectingSVGTargetRules(node)); 96 97 ScopedEventQueue::instance()->enqueueEvent(event); 98 } 99 100 void EventDispatcher::dispatchSimulatedClick(Node* node, PassRefPtr<Event> underlyingEvent, bool sendMouseEvents, bool showPressedLook) 101 { 102 if (node->disabled()) 103 return; 104 105 EventDispatcher dispatcher(node); 106 107 if (!gNodesDispatchingSimulatedClicks) 108 gNodesDispatchingSimulatedClicks = new HashSet<Node*>; 109 else if (gNodesDispatchingSimulatedClicks->contains(node)) 110 return; 111 112 gNodesDispatchingSimulatedClicks->add(node); 113 114 // send mousedown and mouseup before the click, if requested 115 if (sendMouseEvents) 116 dispatcher.dispatchEvent(SimulatedMouseEvent::create(eventNames().mousedownEvent, node->document()->defaultView(), underlyingEvent)); 117 node->setActive(true, showPressedLook); 118 if (sendMouseEvents) 119 dispatcher.dispatchEvent(SimulatedMouseEvent::create(eventNames().mouseupEvent, node->document()->defaultView(), underlyingEvent)); 120 node->setActive(false); 121 122 // always send click 123 dispatcher.dispatchEvent(SimulatedMouseEvent::create(eventNames().clickEvent, node->document()->defaultView(), underlyingEvent)); 124 125 gNodesDispatchingSimulatedClicks->remove(node); 126 } 127 128 static inline bool isShadowRootOrSVGShadowRoot(const Node* node) 129 { 130 return node->isShadowRoot() || node->isSVGShadowRoot(); 131 } 132 133 PassRefPtr<EventTarget> EventDispatcher::adjustToShadowBoundaries(PassRefPtr<Node> relatedTarget, const Vector<Node*> relatedTargetAncestors) 134 { 135 Vector<EventContext>::const_iterator lowestCommonBoundary = m_ancestors.end(); 136 // Assume divergent boundary is the relatedTarget itself (in other words, related target ancestor chain does not cross any shadow DOM boundaries). 137 Vector<Node*>::const_iterator firstDivergentBoundary = relatedTargetAncestors.begin(); 138 139 Vector<EventContext>::const_iterator targetAncestor = m_ancestors.end(); 140 // Walk down from the top, looking for lowest common ancestor, also monitoring shadow DOM boundaries. 141 bool diverged = false; 142 for (Vector<Node*>::const_iterator i = relatedTargetAncestors.end() - 1; i >= relatedTargetAncestors.begin(); --i) { 143 if (diverged) { 144 if (isShadowRootOrSVGShadowRoot(*i)) { 145 firstDivergentBoundary = i + 1; 146 break; 147 } 148 continue; 149 } 150 151 if (targetAncestor == m_ancestors.begin()) { 152 diverged = true; 153 continue; 154 } 155 156 targetAncestor--; 157 158 if (isShadowRootOrSVGShadowRoot(*i)) 159 lowestCommonBoundary = targetAncestor; 160 161 if ((*i) != (*targetAncestor).node()) 162 diverged = true; 163 } 164 165 if (!diverged) { 166 // The relatedTarget is an ancestor or shadowHost of the target. 167 if (m_node->shadowHost() == relatedTarget.get()) 168 lowestCommonBoundary = m_ancestors.begin(); 169 } else if ((*firstDivergentBoundary) == m_node.get()) { 170 // Since ancestors does not contain target itself, we must account 171 // for the possibility that target is a shadowHost of relatedTarget 172 // and thus serves as the lowestCommonBoundary. 173 // Luckily, in this case the firstDivergentBoundary is target. 174 lowestCommonBoundary = m_ancestors.begin(); 175 } 176 177 // Trim ancestors to lowestCommonBoundary to keep events inside of the common shadow DOM subtree. 178 if (lowestCommonBoundary != m_ancestors.end()) 179 m_ancestors.shrink(lowestCommonBoundary - m_ancestors.begin()); 180 // Set event's related target to the first encountered shadow DOM boundary in the divergent subtree. 181 return firstDivergentBoundary != relatedTargetAncestors.begin() ? *firstDivergentBoundary : relatedTarget; 182 } 183 184 inline static bool ancestorsCrossShadowBoundaries(const Vector<EventContext>& ancestors) 185 { 186 return ancestors.isEmpty() || ancestors.first().node() == ancestors.last().node(); 187 } 188 189 // FIXME: Once https://bugs.webkit.org/show_bug.cgi?id=52963 lands, this should 190 // be greatly improved. See https://bugs.webkit.org/show_bug.cgi?id=54025. 191 PassRefPtr<EventTarget> EventDispatcher::adjustRelatedTarget(Event* event, PassRefPtr<EventTarget> prpRelatedTarget) 192 { 193 if (!prpRelatedTarget) 194 return 0; 195 196 RefPtr<Node> relatedTarget = prpRelatedTarget->toNode(); 197 if (!relatedTarget) 198 return 0; 199 200 Node* target = m_node.get(); 201 if (!target) 202 return prpRelatedTarget; 203 204 ensureEventAncestors(event); 205 206 // Calculate early if the common boundary is even possible by looking at 207 // ancestors size and if the retargeting has occured (indicating the presence of shadow DOM boundaries). 208 // If there are no boundaries detected, the target and related target can't have a common boundary. 209 bool noCommonBoundary = ancestorsCrossShadowBoundaries(m_ancestors); 210 211 Vector<Node*> relatedTargetAncestors; 212 Node* outermostShadowBoundary = relatedTarget.get(); 213 for (Node* n = outermostShadowBoundary; n; n = n->parentOrHostNode()) { 214 if (isShadowRootOrSVGShadowRoot(n)) 215 outermostShadowBoundary = n->parentOrHostNode(); 216 if (!noCommonBoundary) 217 relatedTargetAncestors.append(n); 218 } 219 220 // Short-circuit the fast case when we know there is no need to calculate a common boundary. 221 if (noCommonBoundary) 222 return outermostShadowBoundary; 223 224 return adjustToShadowBoundaries(relatedTarget.release(), relatedTargetAncestors); 225 } 226 227 EventDispatcher::EventDispatcher(Node* node) 228 : m_node(node) 229 , m_ancestorsInitialized(false) 230 { 231 ASSERT(node); 232 m_view = node->document()->view(); 233 } 234 235 void EventDispatcher::ensureEventAncestors(Event* event) 236 { 237 EventDispatchBehavior behavior = determineDispatchBehavior(event); 238 239 if (!m_node->inDocument()) 240 return; 241 242 if (m_ancestorsInitialized) 243 return; 244 245 m_ancestorsInitialized = true; 246 247 Node* ancestor = m_node.get(); 248 EventTarget* target = eventTargetRespectingSVGTargetRules(ancestor); 249 bool shouldSkipNextAncestor = false; 250 while (true) { 251 bool isSVGShadowRoot = ancestor->isSVGShadowRoot(); 252 if (isSVGShadowRoot || ancestor->isShadowRoot()) { 253 if (behavior == StayInsideShadowDOM) 254 return; 255 #if ENABLE(SVG) 256 ancestor = isSVGShadowRoot ? ancestor->svgShadowHost() : ancestor->shadowHost(); 257 #else 258 ancestor = ancestor->shadowHost(); 259 #endif 260 if (!shouldSkipNextAncestor) 261 target = ancestor; 262 } else 263 ancestor = ancestor->parentNodeGuaranteedHostFree(); 264 265 if (!ancestor) 266 return; 267 268 #if ENABLE(SVG) 269 // Skip SVGShadowTreeRootElement. 270 shouldSkipNextAncestor = ancestor->isSVGShadowRoot(); 271 if (shouldSkipNextAncestor) 272 continue; 273 #endif 274 // FIXME: Unroll the extra loop inside eventTargetRespectingSVGTargetRules into this loop. 275 m_ancestors.append(EventContext(ancestor, eventTargetRespectingSVGTargetRules(ancestor), target)); 276 } 277 } 278 279 bool EventDispatcher::dispatchEvent(PassRefPtr<Event> event) 280 { 281 event->setTarget(eventTargetRespectingSVGTargetRules(m_node.get())); 282 283 ASSERT(!eventDispatchForbidden()); 284 ASSERT(event->target()); 285 ASSERT(!event->type().isNull()); // JavaScript code can create an event with an empty name, but not null. 286 287 RefPtr<EventTarget> originalTarget = event->target(); 288 ensureEventAncestors(event.get()); 289 290 WindowEventContext windowContext(event.get(), m_node.get(), topEventContext()); 291 292 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispatchEvent(m_node->document(), *event, windowContext.window(), m_node.get(), m_ancestors); 293 294 // Give the target node a chance to do some work before DOM event handlers get a crack. 295 void* data = m_node->preDispatchEventHandler(event.get()); 296 if (event->propagationStopped()) 297 goto doneDispatching; 298 299 // Trigger capturing event handlers, starting at the top and working our way down. 300 event->setEventPhase(Event::CAPTURING_PHASE); 301 302 if (windowContext.handleLocalEvents(event.get()) && event->propagationStopped()) 303 goto doneDispatching; 304 305 for (size_t i = m_ancestors.size(); i; --i) { 306 m_ancestors[i - 1].handleLocalEvents(event.get()); 307 if (event->propagationStopped()) 308 goto doneDispatching; 309 } 310 311 event->setEventPhase(Event::AT_TARGET); 312 event->setTarget(originalTarget.get()); 313 event->setCurrentTarget(eventTargetRespectingSVGTargetRules(m_node.get())); 314 m_node->handleLocalEvents(event.get()); 315 if (event->propagationStopped()) 316 goto doneDispatching; 317 318 if (event->bubbles() && !event->cancelBubble()) { 319 // Trigger bubbling event handlers, starting at the bottom and working our way up. 320 event->setEventPhase(Event::BUBBLING_PHASE); 321 322 size_t size = m_ancestors.size(); 323 for (size_t i = 0; i < size; ++i) { 324 m_ancestors[i].handleLocalEvents(event.get()); 325 if (event->propagationStopped() || event->cancelBubble()) 326 goto doneDispatching; 327 } 328 windowContext.handleLocalEvents(event.get()); 329 } 330 331 doneDispatching: 332 event->setTarget(originalTarget.get()); 333 event->setCurrentTarget(0); 334 event->setEventPhase(0); 335 336 // Pass the data from the preDispatchEventHandler to the postDispatchEventHandler. 337 m_node->postDispatchEventHandler(event.get(), data); 338 339 // Call default event handlers. While the DOM does have a concept of preventing 340 // default handling, the detail of which handlers are called is an internal 341 // implementation detail and not part of the DOM. 342 if (!event->defaultPrevented() && !event->defaultHandled()) { 343 // Non-bubbling events call only one default event handler, the one for the target. 344 m_node->defaultEventHandler(event.get()); 345 ASSERT(!event->defaultPrevented()); 346 if (event->defaultHandled()) 347 goto doneWithDefault; 348 // For bubbling events, call default event handlers on the same targets in the 349 // same order as the bubbling phase. 350 if (event->bubbles()) { 351 size_t size = m_ancestors.size(); 352 for (size_t i = 0; i < size; ++i) { 353 m_ancestors[i].node()->defaultEventHandler(event.get()); 354 ASSERT(!event->defaultPrevented()); 355 if (event->defaultHandled()) 356 goto doneWithDefault; 357 } 358 } 359 } 360 361 doneWithDefault: 362 363 // Ensure that after event dispatch, the event's target object is the 364 // outermost shadow DOM boundary. 365 event->setTarget(windowContext.target()); 366 event->setCurrentTarget(0); 367 InspectorInstrumentation::didDispatchEvent(cookie); 368 369 return !event->defaultPrevented(); 370 } 371 372 const EventContext* EventDispatcher::topEventContext() 373 { 374 return m_ancestors.isEmpty() ? 0 : &m_ancestors.last(); 375 } 376 377 EventDispatchBehavior EventDispatcher::determineDispatchBehavior(Event* event) 378 { 379 // Per XBL 2.0 spec, mutation events should never cross shadow DOM boundary: 380 // http://dev.w3.org/2006/xbl2/#event-flow-and-targeting-across-shadow-s 381 if (event->isMutationEvent()) 382 return StayInsideShadowDOM; 383 384 // WebKit never allowed selectstart event to cross the the shadow DOM boundary. 385 // Changing this breaks existing sites. 386 // See https://bugs.webkit.org/show_bug.cgi?id=52195 for details. 387 if (event->type() == eventNames().selectstartEvent) 388 return StayInsideShadowDOM; 389 390 return RetargetEvent; 391 } 392 393 } 394 395