EventDispatcher.h (13416B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifdef MOZILLA_INTERNAL_API 8 # ifndef mozilla_EventDispatcher_h_ 9 # define mozilla_EventDispatcher_h_ 10 11 # include "mozilla/EventForwards.h" 12 # include "mozilla/Maybe.h" 13 # include "mozilla/dom/BindingDeclarations.h" 14 # include "mozilla/dom/Touch.h" 15 # include "nsCOMPtr.h" 16 # include "nsTArray.h" 17 18 // Microsoft's API Name hackery sucks 19 # undef CreateEvent 20 21 class nsIContent; 22 class nsPresContext; 23 24 template <class E> 25 class nsCOMArray; 26 27 namespace mozilla { 28 namespace dom { 29 class Event; 30 class EventTarget; 31 } // namespace dom 32 33 /** 34 * About event dispatching: 35 * When either EventDispatcher::Dispatch or 36 * EventDispatcher::DispatchDOMEvent is called an event target chain is 37 * created. EventDispatcher creates the chain by calling GetEventTargetParent 38 * on each event target and the creation continues until either the mCanHandle 39 * member of the EventChainPreVisitor object is false or the mParentTarget 40 * does not point to a new target. The event target chain is created in the 41 * heap. 42 * 43 * If the event needs retargeting, mEventTargetAtParent must be set in 44 * GetEventTargetParent. 45 * 46 * The capture, target and bubble phases of the event dispatch are handled 47 * by iterating through the event target chain. Iteration happens twice, 48 * first for the default event group and then for the system event group. 49 * While dispatching the event for the system event group PostHandleEvent 50 * is called right after calling event listener for the current event target. 51 */ 52 53 class MOZ_STACK_CLASS EventChainVisitor { 54 public: 55 // For making creators of this class instances guarantee the lifetime of 56 // aPresContext, this needs to be marked as MOZ_CAN_RUN_SCRIPT. 57 MOZ_CAN_RUN_SCRIPT 58 EventChainVisitor(nsPresContext* aPresContext, WidgetEvent* aEvent, 59 dom::Event* aDOMEvent, 60 nsEventStatus aEventStatus = nsEventStatus_eIgnore) 61 : mPresContext(aPresContext), 62 mEvent(aEvent), 63 mDOMEvent(aDOMEvent), 64 mEventStatus(aEventStatus), 65 mItemFlags(0) {} 66 67 /** 68 * The prescontext, possibly nullptr. 69 * Note that the lifetime of mPresContext is guaranteed by the creators. 70 */ 71 MOZ_KNOWN_LIVE nsPresContext* const mPresContext; 72 73 /** 74 * The WidgetEvent which is being dispatched. Never nullptr. 75 */ 76 WidgetEvent* const mEvent; 77 78 /** 79 * The DOM Event assiciated with the mEvent. Possibly nullptr if a DOM Event 80 * is not (yet) created. 81 */ 82 dom::Event* mDOMEvent; 83 84 /** 85 * The status of the event. 86 * @see nsEventStatus.h 87 */ 88 nsEventStatus mEventStatus; 89 90 /** 91 * Bits for items in the event target chain. 92 * Set in GetEventTargetParent() and used in PostHandleEvent(). 93 * 94 * @note These bits are different for each item in the event target chain. 95 * It is up to the Pre/PostHandleEvent implementation to decide how to 96 * use these bits. 97 * 98 * @note Using uint16_t because that is used also in EventTargetChainItem. 99 */ 100 uint16_t mItemFlags; 101 102 /** 103 * Data for items in the event target chain. 104 * Set in GetEventTargetParent() and used in PostHandleEvent(). 105 * 106 * @note This data is different for each item in the event target chain. 107 * It is up to the Pre/PostHandleEvent implementation to decide how to 108 * use this. 109 */ 110 nsCOMPtr<nsISupports> mItemData; 111 }; 112 113 class MOZ_STACK_CLASS EventChainPreVisitor final : public EventChainVisitor { 114 public: 115 MOZ_CAN_RUN_SCRIPT 116 EventChainPreVisitor(nsPresContext* aPresContext, WidgetEvent* aEvent, 117 dom::Event* aDOMEvent, nsEventStatus aEventStatus, 118 bool aIsInAnon, 119 dom::EventTarget* aTargetInKnownToBeHandledScope) 120 : EventChainVisitor(aPresContext, aEvent, aDOMEvent, aEventStatus), 121 mCanHandle(true), 122 mAutomaticChromeDispatch(true), 123 mForceContentDispatch(false), 124 mRelatedTargetIsInAnon(false), 125 mOriginalTargetIsInAnon(aIsInAnon), 126 mWantsWillHandleEvent(false), 127 mMayHaveListenerManager(true), 128 mWantsPreHandleEvent(false), 129 mRootOfClosedTree(false), 130 mItemInShadowTree(false), 131 mParentIsSlotInClosedTree(false), 132 mParentIsChromeHandler(false), 133 mRelatedTargetRetargetedInCurrentScope(false), 134 mIgnoreBecauseOfShadowDOM(false), 135 mWantsActivationBehavior(false), 136 mMaybeUncancelable(false), 137 mParentTarget(nullptr), 138 mEventTargetAtParent(nullptr), 139 mRetargetedRelatedTarget(nullptr), 140 mTargetInKnownToBeHandledScope(aTargetInKnownToBeHandledScope) {} 141 142 void Reset() { 143 mItemFlags = 0; 144 mItemData = nullptr; 145 mCanHandle = true; 146 mAutomaticChromeDispatch = true; 147 mForceContentDispatch = false; 148 mWantsWillHandleEvent = false; 149 mMayHaveListenerManager = true; 150 mWantsPreHandleEvent = false; 151 mRootOfClosedTree = false; 152 mItemInShadowTree = false; 153 mParentIsSlotInClosedTree = false; 154 mParentIsChromeHandler = false; 155 // Note, we don't clear mRelatedTargetRetargetedInCurrentScope explicitly, 156 // since it is used during event path creation to indicate whether 157 // relatedTarget may need to be retargeted. 158 mIgnoreBecauseOfShadowDOM = false; 159 mWantsActivationBehavior = false; 160 mParentTarget = nullptr; 161 mEventTargetAtParent = nullptr; 162 mRetargetedRelatedTarget = nullptr; 163 mRetargetedTouchTargets.reset(); 164 } 165 166 dom::EventTarget* GetParentTarget() { return mParentTarget; } 167 168 void SetParentTarget(dom::EventTarget* aParentTarget, bool aIsChromeHandler) { 169 mParentTarget = aParentTarget; 170 if (mParentTarget) { 171 mParentIsChromeHandler = aIsChromeHandler; 172 } 173 } 174 175 void IgnoreCurrentTargetBecauseOfShadowDOMRetargeting(); 176 177 /** 178 * Member that must be set in GetEventTargetParent by event targets. If set to 179 * false, indicates that this event target will not be handling the event and 180 * construction of the event target chain is complete. The target that sets 181 * mCanHandle to false is NOT included in the event target chain. 182 */ 183 bool mCanHandle; 184 185 /** 186 * If mCanHandle is false and mAutomaticChromeDispatch is also false 187 * event will not be dispatched to the chrome event handler. 188 */ 189 bool mAutomaticChromeDispatch; 190 191 /** 192 * If mForceContentDispatch is set to true, 193 * content dispatching is not disabled for this event target. 194 * FIXME! This is here for backward compatibility. Bug 329119 195 */ 196 bool mForceContentDispatch; 197 198 /** 199 * true if it is known that related target is or is a descendant of an 200 * element which is anonymous for events. 201 */ 202 bool mRelatedTargetIsInAnon; 203 204 /** 205 * true if the original target of the event is inside anonymous content. 206 * This is set before calling GetEventTargetParent on event targets. 207 */ 208 bool mOriginalTargetIsInAnon; 209 210 /** 211 * Whether or not EventTarget::WillHandleEvent will be 212 * called. Default is false; 213 */ 214 bool mWantsWillHandleEvent; 215 216 /** 217 * If it is known that the current target doesn't have a listener manager 218 * when GetEventTargetParent is called, set this to false. 219 */ 220 bool mMayHaveListenerManager; 221 222 /** 223 * Whether or not EventTarget::PreHandleEvent will be called. Default is 224 * false; 225 */ 226 bool mWantsPreHandleEvent; 227 228 /** 229 * True if the current target is either closed ShadowRoot or root of 230 * chrome only access tree (for example native anonymous content). 231 */ 232 bool mRootOfClosedTree; 233 234 /** 235 * If target is node and its root is a shadow root. 236 * https://dom.spec.whatwg.org/#event-path-item-in-shadow-tree 237 */ 238 bool mItemInShadowTree; 239 240 /** 241 * True if mParentTarget is HTMLSlotElement in a closed shadow tree and the 242 * current target is assigned to that slot. 243 */ 244 bool mParentIsSlotInClosedTree; 245 246 /** 247 * True if mParentTarget is a chrome handler in the event path. 248 */ 249 bool mParentIsChromeHandler; 250 251 /** 252 * True if event's related target has been already retargeted in the 253 * current 'scope'. This should be set to false initially and whenever 254 * event path creation crosses shadow boundary. 255 */ 256 bool mRelatedTargetRetargetedInCurrentScope; 257 258 /** 259 * True if Shadow DOM relatedTarget retargeting causes the current item 260 * to not show up in the event path. 261 */ 262 bool mIgnoreBecauseOfShadowDOM; 263 264 /* 265 * True if the activation behavior of the current item should run 266 * See activationTarget in https://dom.spec.whatwg.org/#concept-event-dispatch 267 */ 268 bool mWantsActivationBehavior; 269 270 /* 271 * Some events will be set uncancelable if we know they won't be default 272 * prevented. If mMaybeUncancelable is true, we haven't found something 273 * that might default prevent the event, like a non-passive listener. 274 * https://w3c.github.io/touch-events/#cancelability 275 */ 276 bool mMaybeUncancelable; 277 278 private: 279 /** 280 * Parent item in the event target chain. 281 */ 282 dom::EventTarget* mParentTarget; 283 284 public: 285 /** 286 * If the event needs to be retargeted, this is the event target, 287 * which should be used when the event is handled at mParentTarget. 288 */ 289 dom::EventTarget* mEventTargetAtParent; 290 291 /** 292 * If the related target of the event needs to be retargeted, set this 293 * to a new EventTarget. 294 */ 295 dom::EventTarget* mRetargetedRelatedTarget; 296 297 /** 298 * If mEvent is a WidgetTouchEvent and its mTouches needs retargeting, 299 * set the targets to this array. The array should contain one entry per 300 * each object in WidgetTouchEvent::mTouches. 301 */ 302 mozilla::Maybe<nsTArray<RefPtr<dom::EventTarget>>> mRetargetedTouchTargets; 303 304 /** 305 * Set to the value of mEvent->mTarget of the previous scope in case of 306 * Shadow DOM or such, and if there is no anonymous content this just points 307 * to the initial target. 308 */ 309 dom::EventTarget* mTargetInKnownToBeHandledScope; 310 }; 311 312 class MOZ_STACK_CLASS EventChainPostVisitor final 313 : public mozilla::EventChainVisitor { 314 public: 315 // Note that for making guarantee the lifetime of mPresContext and mDOMEvent, 316 // creators should guarantee that aOther won't be deleted while the instance 317 // of this class is alive. 318 MOZ_CAN_RUN_SCRIPT 319 explicit EventChainPostVisitor(EventChainVisitor& aOther) 320 : EventChainVisitor(aOther.mPresContext, aOther.mEvent, 321 MOZ_KnownLive(aOther.mDOMEvent), 322 aOther.mEventStatus) {} 323 }; 324 325 /** 326 * If an EventDispatchingCallback object is passed to Dispatch, 327 * its HandleEvent method is called after handling the default event group, 328 * before handling the system event group. 329 * This is used in PresShell. 330 */ 331 class MOZ_STACK_CLASS EventDispatchingCallback { 332 public: 333 MOZ_CAN_RUN_SCRIPT 334 virtual void HandleEvent(EventChainPostVisitor& aVisitor) = 0; 335 }; 336 337 /** 338 * The generic class for event dispatching. 339 * Must not be used outside Gecko! 340 */ 341 class EventDispatcher { 342 public: 343 /** 344 * If the target of aEvent is set before calling this method, the target of 345 * aEvent is used as the target (unless there is event 346 * retargeting) and the originalTarget of the DOM Event. 347 * aTarget is always used as the starting point for constructing the event 348 * target chain, no matter what the value of aEvent->mTarget is. 349 * In other words, aEvent->mTarget is only a property of the event and it has 350 * nothing to do with the construction of the event target chain. 351 * Neither aTarget nor aEvent is allowed to be nullptr. 352 * 353 * If aTargets is non-null, event target chain will be created, but 354 * event won't be handled. In this case aEvent->mMessage should be 355 * eVoidEvent. 356 * @note Use this method when dispatching a WidgetEvent. 357 */ 358 MOZ_CAN_RUN_SCRIPT static nsresult Dispatch( 359 dom::EventTarget* aTarget, nsPresContext* aPresContext, 360 WidgetEvent* aEvent, dom::Event* aDOMEvent = nullptr, 361 nsEventStatus* aEventStatus = nullptr, 362 EventDispatchingCallback* aCallback = nullptr, 363 nsTArray<dom::EventTarget*>* aTargets = nullptr); 364 365 /** 366 * Dispatches an event. 367 * If aDOMEvent is not nullptr, it is used for dispatching 368 * (aEvent can then be nullptr) and (if aDOMEvent is not |trusted| already), 369 * the |trusted| flag is set if the caller uses the system principal. 370 * Otherwise this works like EventDispatcher::Dispatch. 371 * @note Use this method when dispatching a dom::Event. 372 */ 373 MOZ_CAN_RUN_SCRIPT static nsresult DispatchDOMEvent( 374 dom::EventTarget* aTarget, WidgetEvent* aEvent, dom::Event* aDOMEvent, 375 nsPresContext* aPresContext, nsEventStatus* aEventStatus); 376 377 /** 378 * Creates a DOM Event. Returns null if the event type is unsupported. 379 */ 380 static already_AddRefed<dom::Event> CreateEvent( 381 dom::EventTarget* aOwner, nsPresContext* aPresContext, 382 WidgetEvent* aEvent, const nsAString& aEventType, 383 dom::CallerType aCallerType = dom::CallerType::System); 384 385 static void GetComposedPathFor(WidgetEvent* aEvent, 386 nsTArray<RefPtr<dom::EventTarget>>& aPath); 387 388 /** 389 * Called at shutting down. 390 */ 391 static void Shutdown(); 392 }; 393 394 } // namespace mozilla 395 396 # endif // mozilla_EventDispatcher_h_ 397 #endif