Line data Source code
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 : #ifndef mozilla_EventStateManager_h_
8 : #define mozilla_EventStateManager_h_
9 :
10 : #include "mozilla/EventForwards.h"
11 :
12 : #include "nsIObserver.h"
13 : #include "nsWeakReference.h"
14 : #include "nsCOMPtr.h"
15 : #include "nsCOMArray.h"
16 : #include "nsCycleCollectionParticipant.h"
17 : #include "mozilla/TimeStamp.h"
18 : #include "nsIFrame.h"
19 : #include "Units.h"
20 :
21 : class nsFrameLoader;
22 : class nsIContent;
23 : class nsIDocument;
24 : class nsIDocShell;
25 : class nsIDocShellTreeItem;
26 : class imgIContainer;
27 : class EnterLeaveDispatcher;
28 : class nsIContentViewer;
29 : class nsIScrollableFrame;
30 : class nsITimer;
31 : class nsPresContext;
32 :
33 : namespace mozilla {
34 :
35 : class EnterLeaveDispatcher;
36 : class EventStates;
37 : class IMEContentObserver;
38 : class ScrollbarsForWheel;
39 : class WheelTransaction;
40 :
41 : namespace dom {
42 : class DataTransfer;
43 : class Element;
44 : class TabParent;
45 : } // namespace dom
46 :
47 0 : class OverOutElementsWrapper final : public nsISupports
48 : {
49 : ~OverOutElementsWrapper();
50 :
51 : public:
52 : OverOutElementsWrapper();
53 :
54 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
55 4 : NS_DECL_CYCLE_COLLECTION_CLASS(OverOutElementsWrapper)
56 :
57 : WeakFrame mLastOverFrame;
58 :
59 : nsCOMPtr<nsIContent> mLastOverElement;
60 :
61 : // The last element on which we fired a over event, or null if
62 : // the last over event we fired has finished processing.
63 : nsCOMPtr<nsIContent> mFirstOverEventElement;
64 :
65 : // The last element on which we fired a out event, or null if
66 : // the last out event we fired has finished processing.
67 : nsCOMPtr<nsIContent> mFirstOutEventElement;
68 : };
69 :
70 : class EventStateManager : public nsSupportsWeakReference,
71 : public nsIObserver
72 : {
73 : friend class mozilla::EnterLeaveDispatcher;
74 : friend class mozilla::ScrollbarsForWheel;
75 : friend class mozilla::WheelTransaction;
76 :
77 : virtual ~EventStateManager();
78 :
79 : public:
80 : EventStateManager();
81 :
82 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
83 : NS_DECL_NSIOBSERVER
84 :
85 : nsresult Init();
86 : nsresult Shutdown();
87 :
88 : /* The PreHandleEvent method is called before event dispatch to either
89 : * the DOM or frames. Any processing which must not be prevented or
90 : * cancelled should occur here. Any processing which is intended to
91 : * be conditional based on either DOM or frame processing should occur in
92 : * PostHandleEvent. Any centralized event processing which must occur before
93 : * DOM or frame event handling should occur here as well.
94 : */
95 : nsresult PreHandleEvent(nsPresContext* aPresContext,
96 : WidgetEvent* aEvent,
97 : nsIFrame* aTargetFrame,
98 : nsIContent* aTargetContent,
99 : nsEventStatus* aStatus);
100 :
101 : /* The PostHandleEvent method should contain all system processing which
102 : * should occur conditionally based on DOM or frame processing. It should
103 : * also contain any centralized event processing which must occur after
104 : * DOM and frame processing.
105 : */
106 : nsresult PostHandleEvent(nsPresContext* aPresContext,
107 : WidgetEvent* aEvent,
108 : nsIFrame* aTargetFrame,
109 : nsEventStatus* aStatus);
110 :
111 : void PostHandleKeyboardEvent(WidgetKeyboardEvent* aKeyboardEvent,
112 : nsEventStatus& aStatus);
113 :
114 : /**
115 : * DispatchLegacyMouseScrollEvents() dispatches eLegacyMouseLineOrPageScroll
116 : * event and eLegacyMousePixelScroll event for compatibility with old Gecko.
117 : */
118 : void DispatchLegacyMouseScrollEvents(nsIFrame* aTargetFrame,
119 : WidgetWheelEvent* aEvent,
120 : nsEventStatus* aStatus);
121 :
122 : void NotifyDestroyPresContext(nsPresContext* aPresContext);
123 : void SetPresContext(nsPresContext* aPresContext);
124 : void ClearFrameRefs(nsIFrame* aFrame);
125 :
126 : nsIFrame* GetEventTarget();
127 : already_AddRefed<nsIContent> GetEventTargetContent(WidgetEvent* aEvent);
128 :
129 : /**
130 : * Notify that the given NS_EVENT_STATE_* bit has changed for this content.
131 : * @param aContent Content which has changed states
132 : * @param aState Corresponding state flags such as NS_EVENT_STATE_FOCUS
133 : * @return Whether the content was able to change all states. Returns false
134 : * if a resulting DOM event causes the content node passed in
135 : * to not change states. Note, the frame for the content may
136 : * change as a result of the content state change, because of
137 : * frame reconstructions that may occur, but this does not
138 : * affect the return value.
139 : */
140 : bool SetContentState(nsIContent* aContent, EventStates aState);
141 : void ContentRemoved(nsIDocument* aDocument, nsIContent* aContent);
142 : bool EventStatusOK(WidgetGUIEvent* aEvent);
143 :
144 : /**
145 : * EventStateManager stores IMEContentObserver while it's observing contents.
146 : * Following mehtods are called by IMEContentObserver when it starts to
147 : * observe or stops observing the content.
148 : */
149 : void OnStartToObserveContent(IMEContentObserver* aIMEContentObserver);
150 : void OnStopObservingContent(IMEContentObserver* aIMEContentObserver);
151 :
152 : /**
153 : * TryToFlushPendingNotificationsToIME() suggests flushing pending
154 : * notifications to IME to IMEContentObserver.
155 : * Doesn't do anything in child processes where flushing happens
156 : * asynchronously.
157 : */
158 : void TryToFlushPendingNotificationsToIME();
159 :
160 : /**
161 : * Register accesskey on the given element. When accesskey is activated then
162 : * the element will be notified via nsIContent::PerformAccesskey() method.
163 : *
164 : * @param aContent the given element
165 : * @param aKey accesskey
166 : */
167 : void RegisterAccessKey(nsIContent* aContent, uint32_t aKey);
168 :
169 : /**
170 : * Unregister accesskey for the given element.
171 : *
172 : * @param aContent the given element
173 : * @param aKey accesskey
174 : */
175 : void UnregisterAccessKey(nsIContent* aContent, uint32_t aKey);
176 :
177 : /**
178 : * Get accesskey registered on the given element or 0 if there is none.
179 : *
180 : * @param aContent the given element (must not be null)
181 : * @return registered accesskey
182 : */
183 : uint32_t GetRegisteredAccessKey(nsIContent* aContent);
184 :
185 : static void GetAccessKeyLabelPrefix(dom::Element* aElement, nsAString& aPrefix);
186 :
187 0 : bool HandleAccessKey(WidgetKeyboardEvent* aEvent,
188 : nsPresContext* aPresContext,
189 : nsTArray<uint32_t>& aAccessCharCodes,
190 : int32_t aModifierMask,
191 : bool aMatchesContentAccessKey)
192 : {
193 0 : return HandleAccessKey(aEvent, aPresContext, aAccessCharCodes,
194 : aMatchesContentAccessKey, nullptr,
195 0 : eAccessKeyProcessingNormal, aModifierMask);
196 : }
197 :
198 : nsresult SetCursor(int32_t aCursor, imgIContainer* aContainer,
199 : bool aHaveHotspot, float aHotspotX, float aHotspotY,
200 : nsIWidget* aWidget, bool aLockCursor);
201 :
202 0 : static void StartHandlingUserInput()
203 : {
204 0 : ++sUserInputEventDepth;
205 0 : ++sUserInputCounter;
206 0 : if (sUserInputEventDepth == 1) {
207 0 : sLatestUserInputStart = sHandlingInputStart = TimeStamp::Now();
208 : }
209 0 : }
210 :
211 0 : static void StopHandlingUserInput()
212 : {
213 0 : --sUserInputEventDepth;
214 0 : if (sUserInputEventDepth == 0) {
215 0 : sHandlingInputStart = TimeStamp();
216 : }
217 0 : }
218 :
219 0 : static TimeStamp GetHandlingInputStart() {
220 0 : return sHandlingInputStart;
221 : }
222 :
223 : /**
224 : * Returns true if the current code is being executed as a result of
225 : * user input. This includes anything that is initiated by user,
226 : * with the exception of page load events or mouse over events. If
227 : * this method is called from asynchronously executed code, such as
228 : * during layout reflows, it will return false.
229 : */
230 : static bool IsHandlingUserInput();
231 :
232 : /**
233 : * Get the number of user inputs handled since process start. This
234 : * includes anything that is initiated by user, with the exception
235 : * of page load events or mouse over events.
236 : */
237 0 : static uint64_t UserInputCount()
238 : {
239 0 : return sUserInputCounter;
240 : }
241 :
242 : /**
243 : * Get the timestamp at which the latest user input was handled.
244 : *
245 : * Guaranteed to be monotonic. Until the first user input, return
246 : * the epoch.
247 : */
248 0 : static TimeStamp LatestUserInputStart()
249 : {
250 0 : return sLatestUserInputStart;
251 : }
252 :
253 0 : nsPresContext* GetPresContext() { return mPresContext; }
254 :
255 136 : NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(EventStateManager,
256 : nsIObserver)
257 :
258 : static nsIDocument* sMouseOverDocument;
259 :
260 14 : static EventStateManager* GetActiveEventStateManager() { return sActiveESM; }
261 :
262 : // Sets aNewESM to be the active event state manager, and
263 : // if aContent is non-null, marks the object as active.
264 : static void SetActiveManager(EventStateManager* aNewESM,
265 : nsIContent* aContent);
266 :
267 : // Sets the full-screen event state on aElement to aIsFullScreen.
268 : static void SetFullScreenState(dom::Element* aElement, bool aIsFullScreen);
269 :
270 : static bool IsRemoteTarget(nsIContent* aTarget);
271 :
272 : // Returns true if the given WidgetWheelEvent will resolve to a scroll action.
273 : static bool WheelEventIsScrollAction(WidgetWheelEvent* aEvent);
274 :
275 : // Returns user-set multipliers for a wheel event.
276 : static void GetUserPrefsForWheelEvent(WidgetWheelEvent* aEvent,
277 : double* aOutMultiplierX,
278 : double* aOutMultiplierY);
279 :
280 : // Returns whether or not a frame can be vertically scrolled with a mouse
281 : // wheel (as opposed to, say, a selection or touch scroll).
282 : static bool CanVerticallyScrollFrameWithWheel(nsIFrame* aFrame);
283 :
284 : // Holds the point in screen coords that a mouse event was dispatched to,
285 : // before we went into pointer lock mode. This is constantly updated while
286 : // the pointer is not locked, but we don't update it while the pointer is
287 : // locked. This is used by dom::Event::GetScreenCoords() to make mouse
288 : // events' screen coord appear frozen at the last mouse position while
289 : // the pointer is locked.
290 : static CSSIntPoint sLastScreenPoint;
291 :
292 : // Holds the point in client coords of the last mouse event. Used by
293 : // dom::Event::GetClientCoords() to make mouse events' client coords appear
294 : // frozen at the last mouse position while the pointer is locked.
295 : static CSSIntPoint sLastClientPoint;
296 :
297 : static bool sIsPointerLocked;
298 : static nsWeakPtr sPointerLockedElement;
299 : static nsWeakPtr sPointerLockedDoc;
300 :
301 : /**
302 : * If the absolute values of mMultiplierX and/or mMultiplierY are equal or
303 : * larger than this value, the computed scroll amount isn't rounded down to
304 : * the page width or height.
305 : */
306 : enum {
307 : MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL = 1000
308 : };
309 :
310 : protected:
311 : /**
312 : * Prefs class capsules preference management.
313 : */
314 : class Prefs
315 : {
316 : public:
317 0 : static bool KeyCausesActivation() { return sKeyCausesActivation; }
318 0 : static bool ClickHoldContextMenu() { return sClickHoldContextMenu; }
319 : static int32_t ChromeAccessModifierMask();
320 : static int32_t ContentAccessModifierMask();
321 :
322 : static void Init();
323 : static void OnChange(const char* aPrefName, void*);
324 : static void Shutdown();
325 :
326 : private:
327 : static bool sKeyCausesActivation;
328 : static bool sClickHoldContextMenu;
329 : static int32_t sGenericAccessModifierKey;
330 : static int32_t sChromeAccessModifierMask;
331 : static int32_t sContentAccessModifierMask;
332 :
333 : static int32_t GetAccessModifierMask(int32_t aItemType);
334 : };
335 :
336 : /**
337 : * Get appropriate access modifier mask for the aDocShell. Returns -1 if
338 : * access key isn't available.
339 : */
340 : static int32_t GetAccessModifierMaskFor(nsISupports* aDocShell);
341 :
342 : /*
343 : * If aTargetFrame's widget has a cached cursor value, resets the cursor
344 : * such that the next call to SetCursor on the widget will force an update
345 : * of the native cursor. For use in getting puppet widget to update its
346 : * cursor between mouse exit / enter transitions. This call basically wraps
347 : * nsIWidget ClearCachedCursor.
348 : */
349 : void ClearCachedWidgetCursor(nsIFrame* aTargetFrame);
350 :
351 : void UpdateCursor(nsPresContext* aPresContext,
352 : WidgetEvent* aEvent,
353 : nsIFrame* aTargetFrame,
354 : nsEventStatus* aStatus);
355 : /**
356 : * Turn a GUI mouse/pointer event into a mouse/pointer event targeted at the specified
357 : * content. This returns the primary frame for the content (or null
358 : * if it goes away during the event).
359 : */
360 : nsIFrame* DispatchMouseOrPointerEvent(WidgetMouseEvent* aMouseEvent,
361 : EventMessage aMessage,
362 : nsIContent* aTargetContent,
363 : nsIContent* aRelatedContent);
364 : /**
365 : * Synthesize DOM pointerover and pointerout events
366 : */
367 : void GeneratePointerEnterExit(EventMessage aMessage,
368 : WidgetMouseEvent* aEvent);
369 : /**
370 : * Synthesize DOM and frame mouseover and mouseout events from this
371 : * MOUSE_MOVE or MOUSE_EXIT event.
372 : */
373 : void GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent);
374 : /**
375 : * Tell this ESM and ESMs in parent documents that the mouse is
376 : * over some content in this document.
377 : */
378 : void NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
379 : nsIContent* aContent);
380 : /**
381 : * Tell this ESM and ESMs in affected child documents that the mouse
382 : * has exited this document's currently hovered content.
383 : * @param aMouseEvent the event that triggered the mouseout
384 : * @param aMovingInto the content node we've moved into. This is used to set
385 : * the relatedTarget for mouseout events. Also, if it's non-null
386 : * NotifyMouseOut will NOT change the current hover content to null;
387 : * in that case the caller is responsible for updating hover state.
388 : */
389 : void NotifyMouseOut(WidgetMouseEvent* aMouseEvent,
390 : nsIContent* aMovingInto);
391 : void GenerateDragDropEnterExit(nsPresContext* aPresContext,
392 : WidgetDragEvent* aDragEvent);
393 :
394 : /**
395 : * Return mMouseEnterLeaveHelper or relevant mPointersEnterLeaveHelper elements wrapper.
396 : * If mPointersEnterLeaveHelper does not contain wrapper for pointerId it create new one
397 : */
398 : OverOutElementsWrapper* GetWrapperByEventID(WidgetMouseEvent* aMouseEvent);
399 :
400 : /**
401 : * Fire the dragenter and dragexit/dragleave events when the mouse moves to a
402 : * new target.
403 : *
404 : * @param aRelatedTarget relatedTarget to set for the event
405 : * @param aTargetContent target to set for the event
406 : * @param aTargetFrame target frame for the event
407 : */
408 : void FireDragEnterOrExit(nsPresContext* aPresContext,
409 : WidgetDragEvent* aDragEvent,
410 : EventMessage aMessage,
411 : nsIContent* aRelatedTarget,
412 : nsIContent* aTargetContent,
413 : AutoWeakFrame& aTargetFrame);
414 : /**
415 : * Update the initial drag session data transfer with any changes that occur
416 : * on cloned data transfer objects used for events.
417 : */
418 : void UpdateDragDataTransfer(WidgetDragEvent* dragEvent);
419 :
420 : static nsresult InitAndDispatchClickEvent(WidgetMouseEvent* aEvent,
421 : nsEventStatus* aStatus,
422 : EventMessage aMessage,
423 : nsIPresShell* aPresShell,
424 : nsIContent* aMouseTarget,
425 : AutoWeakFrame aCurrentTarget,
426 : bool aNoContentDispatch);
427 : nsresult SetClickCount(WidgetMouseEvent* aEvent, nsEventStatus* aStatus);
428 : nsresult CheckForAndDispatchClick(WidgetMouseEvent* aEvent,
429 : nsEventStatus* aStatus);
430 : void EnsureDocument(nsPresContext* aPresContext);
431 : void FlushPendingEvents(nsPresContext* aPresContext);
432 :
433 : /**
434 : * The phases of HandleAccessKey processing. See below.
435 : */
436 : typedef enum {
437 : eAccessKeyProcessingNormal = 0,
438 : eAccessKeyProcessingUp,
439 : eAccessKeyProcessingDown
440 : } ProcessingAccessKeyState;
441 :
442 : /**
443 : * Access key handling. If there is registered content for the accesskey
444 : * given by the key event and modifier mask then call
445 : * content.PerformAccesskey(), otherwise call HandleAccessKey() recursively,
446 : * on descendant docshells first, then on the ancestor (with |aBubbledFrom|
447 : * set to the docshell associated with |this|), until something matches.
448 : *
449 : * @param aEvent the keyboard event triggering the acccess key
450 : * @param aPresContext the presentation context
451 : * @param aAccessCharCodes list of charcode candidates
452 : * @param aMatchesContentAccessKey true if the content accesskey modifier is pressed
453 : * @param aBubbledFrom is used by an ancestor to avoid calling HandleAccessKey()
454 : * on the child the call originally came from, i.e. this is the child
455 : * that recursively called us in its Up phase. The initial caller
456 : * passes |nullptr| here. This is to avoid an infinite loop.
457 : * @param aAccessKeyState Normal, Down or Up processing phase (see enums
458 : * above). The initial event receiver uses 'normal', then 'down' when
459 : * processing children and Up when recursively calling its ancestor.
460 : * @param aModifierMask modifier mask for the key event
461 : */
462 : bool HandleAccessKey(WidgetKeyboardEvent* aEvent,
463 : nsPresContext* aPresContext,
464 : nsTArray<uint32_t>& aAccessCharCodes,
465 : bool aMatchesContentAccessKey,
466 : nsIDocShellTreeItem* aBubbledFrom,
467 : ProcessingAccessKeyState aAccessKeyState,
468 : int32_t aModifierMask);
469 :
470 : bool ExecuteAccessKey(nsTArray<uint32_t>& aAccessCharCodes,
471 : bool aIsTrustedEvent);
472 :
473 : //---------------------------------------------
474 : // DocShell Focus Traversal Methods
475 : //---------------------------------------------
476 :
477 : nsIContent* GetFocusedContent();
478 : bool IsShellVisible(nsIDocShell* aShell);
479 :
480 : // These functions are for mousewheel and pixel scrolling
481 :
482 : class WheelPrefs
483 : {
484 : public:
485 : static WheelPrefs* GetInstance();
486 : static void Shutdown();
487 :
488 : /**
489 : * ApplyUserPrefsToDelta() overrides the wheel event's delta values with
490 : * user prefs.
491 : */
492 : void ApplyUserPrefsToDelta(WidgetWheelEvent* aEvent);
493 :
494 : /**
495 : * Returns whether or not ApplyUserPrefsToDelta() would change the delta
496 : * values of an event.
497 : */
498 : void GetUserPrefsForEvent(WidgetWheelEvent* aEvent,
499 : double* aOutMultiplierX,
500 : double* aOutMultiplierY);
501 :
502 : /**
503 : * If ApplyUserPrefsToDelta() changed the delta values with customized
504 : * prefs, the overflowDelta values would be inflated.
505 : * CancelApplyingUserPrefsFromOverflowDelta() cancels the inflation.
506 : */
507 : void CancelApplyingUserPrefsFromOverflowDelta(WidgetWheelEvent* aEvent);
508 :
509 : /**
510 : * Computes the default action for the aEvent with the prefs.
511 : */
512 : enum Action : uint8_t
513 : {
514 : ACTION_NONE = 0,
515 : ACTION_SCROLL,
516 : ACTION_HISTORY,
517 : ACTION_ZOOM,
518 : ACTION_LAST = ACTION_ZOOM,
519 : // Following actions are used only by internal processing. So, cannot
520 : // specified by prefs.
521 : ACTION_SEND_TO_PLUGIN
522 : };
523 : Action ComputeActionFor(WidgetWheelEvent* aEvent);
524 :
525 : /**
526 : * NeedToComputeLineOrPageDelta() returns if the aEvent needs to be
527 : * computed the lineOrPageDelta values.
528 : */
529 : bool NeedToComputeLineOrPageDelta(WidgetWheelEvent* aEvent);
530 :
531 : /**
532 : * IsOverOnePageScrollAllowed*() checks whether wheel scroll amount should
533 : * be rounded down to the page width/height (false) or not (true).
534 : */
535 : bool IsOverOnePageScrollAllowedX(WidgetWheelEvent* aEvent);
536 : bool IsOverOnePageScrollAllowedY(WidgetWheelEvent* aEvent);
537 :
538 : /**
539 : * WheelEventsEnabledOnPlugins() returns true if user wants to use mouse
540 : * wheel on plugins.
541 : */
542 : static bool WheelEventsEnabledOnPlugins();
543 :
544 : private:
545 : WheelPrefs();
546 : ~WheelPrefs();
547 :
548 : static void OnPrefChanged(const char* aPrefName, void* aClosure);
549 :
550 : enum Index
551 : {
552 : INDEX_DEFAULT = 0,
553 : INDEX_ALT,
554 : INDEX_CONTROL,
555 : INDEX_META,
556 : INDEX_SHIFT,
557 : INDEX_OS,
558 : COUNT_OF_MULTIPLIERS
559 : };
560 :
561 : /**
562 : * GetIndexFor() returns the index of the members which should be used for
563 : * the aEvent. When only one modifier key of MODIFIER_ALT,
564 : * MODIFIER_CONTROL, MODIFIER_META, MODIFIER_SHIFT or MODIFIER_OS is
565 : * pressed, returns the index for the modifier. Otherwise, this return the
566 : * default index which is used at either no modifier key is pressed or
567 : * two or modifier keys are pressed.
568 : */
569 : Index GetIndexFor(WidgetWheelEvent* aEvent);
570 :
571 : /**
572 : * GetPrefNameBase() returns the base pref name for aEvent.
573 : * It's decided by GetModifierForPref() which modifier should be used for
574 : * the aEvent.
575 : *
576 : * @param aBasePrefName The result, must be "mousewheel.with_*." or
577 : * "mousewheel.default.".
578 : */
579 : void GetBasePrefName(Index aIndex, nsACString& aBasePrefName);
580 :
581 : void Init(Index aIndex);
582 :
583 : void Reset();
584 :
585 : bool mInit[COUNT_OF_MULTIPLIERS];
586 : double mMultiplierX[COUNT_OF_MULTIPLIERS];
587 : double mMultiplierY[COUNT_OF_MULTIPLIERS];
588 : double mMultiplierZ[COUNT_OF_MULTIPLIERS];
589 : Action mActions[COUNT_OF_MULTIPLIERS];
590 : /**
591 : * action values overridden by .override_x pref.
592 : * If an .override_x value is -1, same as the
593 : * corresponding mActions value.
594 : */
595 : Action mOverriddenActionsX[COUNT_OF_MULTIPLIERS];
596 :
597 : static WheelPrefs* sInstance;
598 :
599 : static bool sWheelEventsEnabledOnPlugins;
600 : };
601 :
602 : /**
603 : * DeltaDirection is used for specifying whether the called method should
604 : * handle vertical delta or horizontal delta.
605 : * This is clearer than using bool.
606 : */
607 : enum DeltaDirection
608 : {
609 : DELTA_DIRECTION_X = 0,
610 : DELTA_DIRECTION_Y
611 : };
612 :
613 : struct MOZ_STACK_CLASS EventState
614 : {
615 : bool mDefaultPrevented;
616 : bool mDefaultPreventedByContent;
617 :
618 0 : EventState() :
619 0 : mDefaultPrevented(false), mDefaultPreventedByContent(false)
620 : {
621 0 : }
622 : };
623 :
624 : /**
625 : * SendLineScrollEvent() dispatches a DOMMouseScroll event for the
626 : * WidgetWheelEvent. This method shouldn't be called for non-trusted
627 : * wheel event because it's not necessary for compatiblity.
628 : *
629 : * @param aTargetFrame The event target of wheel event.
630 : * @param aEvent The original Wheel event.
631 : * @param aState The event which should be set to the dispatching
632 : * event. This also returns the dispatched event
633 : * state.
634 : * @param aDelta The delta value of the event.
635 : * @param aDeltaDirection The X/Y direction of dispatching event.
636 : */
637 : void SendLineScrollEvent(nsIFrame* aTargetFrame,
638 : WidgetWheelEvent* aEvent,
639 : EventState& aState,
640 : int32_t aDelta,
641 : DeltaDirection aDeltaDirection);
642 :
643 : /**
644 : * SendPixelScrollEvent() dispatches a MozMousePixelScroll event for the
645 : * WidgetWheelEvent. This method shouldn't be called for non-trusted
646 : * wheel event because it's not necessary for compatiblity.
647 : *
648 : * @param aTargetFrame The event target of wheel event.
649 : * @param aEvent The original Wheel event.
650 : * @param aState The event which should be set to the dispatching
651 : * event. This also returns the dispatched event
652 : * state.
653 : * @param aPixelDelta The delta value of the event.
654 : * @param aDeltaDirection The X/Y direction of dispatching event.
655 : */
656 : void SendPixelScrollEvent(nsIFrame* aTargetFrame,
657 : WidgetWheelEvent* aEvent,
658 : EventState& aState,
659 : int32_t aPixelDelta,
660 : DeltaDirection aDeltaDirection);
661 :
662 : /**
663 : * ComputeScrollTarget() returns the scrollable frame which should be
664 : * scrolled.
665 : *
666 : * @param aTargetFrame The event target of the wheel event.
667 : * @param aEvent The handling mouse wheel event.
668 : * @param aOptions The options for finding the scroll target.
669 : * Callers should use COMPUTE_*.
670 : * @return The scrollable frame which should be scrolled.
671 : */
672 : // These flags are used in ComputeScrollTarget(). Callers should use
673 : // COMPUTE_*.
674 : enum
675 : {
676 : PREFER_MOUSE_WHEEL_TRANSACTION = 0x00000001,
677 : PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS = 0x00000002,
678 : PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS = 0x00000004,
679 : START_FROM_PARENT = 0x00000008,
680 : INCLUDE_PLUGIN_AS_TARGET = 0x00000010
681 : };
682 : enum ComputeScrollTargetOptions
683 : {
684 : // At computing scroll target for legacy mouse events, we should return
685 : // first scrollable element even when it's not scrollable to the direction.
686 : COMPUTE_LEGACY_MOUSE_SCROLL_EVENT_TARGET = 0,
687 : // Default action prefers the scrolled element immediately before if it's
688 : // still under the mouse cursor. Otherwise, it prefers the nearest
689 : // scrollable ancestor which will be scrolled actually.
690 : COMPUTE_DEFAULT_ACTION_TARGET_EXCEPT_PLUGIN =
691 : (PREFER_MOUSE_WHEEL_TRANSACTION |
692 : PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS |
693 : PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS),
694 : // When this is specified, the result may be nsPluginFrame. In such case,
695 : // the frame doesn't have nsIScrollableFrame interface.
696 : COMPUTE_DEFAULT_ACTION_TARGET =
697 : (COMPUTE_DEFAULT_ACTION_TARGET_EXCEPT_PLUGIN |
698 : INCLUDE_PLUGIN_AS_TARGET),
699 : // Look for the nearest scrollable ancestor which can be scrollable with
700 : // aEvent.
701 : COMPUTE_SCROLLABLE_ANCESTOR_ALONG_X_AXIS =
702 : (PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS | START_FROM_PARENT),
703 : COMPUTE_SCROLLABLE_ANCESTOR_ALONG_Y_AXIS =
704 : (PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS | START_FROM_PARENT)
705 : };
706 0 : static ComputeScrollTargetOptions RemovePluginFromTarget(
707 : ComputeScrollTargetOptions aOptions)
708 : {
709 0 : switch (aOptions) {
710 : case COMPUTE_DEFAULT_ACTION_TARGET:
711 0 : return COMPUTE_DEFAULT_ACTION_TARGET_EXCEPT_PLUGIN;
712 : default:
713 0 : MOZ_ASSERT(!(aOptions & INCLUDE_PLUGIN_AS_TARGET));
714 0 : return aOptions;
715 : }
716 : }
717 : nsIFrame* ComputeScrollTarget(nsIFrame* aTargetFrame,
718 : WidgetWheelEvent* aEvent,
719 : ComputeScrollTargetOptions aOptions);
720 :
721 : nsIFrame* ComputeScrollTarget(nsIFrame* aTargetFrame,
722 : double aDirectionX,
723 : double aDirectionY,
724 : WidgetWheelEvent* aEvent,
725 : ComputeScrollTargetOptions aOptions);
726 :
727 : /**
728 : * GetScrollAmount() returns the scroll amount in app uints of one line or
729 : * one page. If the wheel event scrolls a page, returns the page width and
730 : * height. Otherwise, returns line height for both its width and height.
731 : *
732 : * @param aScrollableFrame A frame which will be scrolled by the event.
733 : * The result of ComputeScrollTarget() is
734 : * expected for this value.
735 : * This can be nullptr if there is no scrollable
736 : * frame. Then, this method uses root frame's
737 : * line height or visible area's width and height.
738 : */
739 : nsSize GetScrollAmount(nsPresContext* aPresContext,
740 : WidgetWheelEvent* aEvent,
741 : nsIScrollableFrame* aScrollableFrame);
742 :
743 : /**
744 : * DoScrollText() scrolls the scrollable frame for aEvent.
745 : */
746 : void DoScrollText(nsIScrollableFrame* aScrollableFrame,
747 : WidgetWheelEvent* aEvent);
748 :
749 : void DoScrollHistory(int32_t direction);
750 : void DoScrollZoom(nsIFrame *aTargetFrame, int32_t adjustment);
751 : nsresult GetContentViewer(nsIContentViewer** aCv);
752 : nsresult ChangeTextSize(int32_t change);
753 : nsresult ChangeFullZoom(int32_t change);
754 :
755 : /**
756 : * DeltaAccumulator class manages delta values for dispatching DOMMouseScroll
757 : * event. If wheel events are caused by pixel scroll only devices or
758 : * the delta values are customized by prefs, this class stores the delta
759 : * values and set lineOrPageDelta values.
760 : */
761 : class DeltaAccumulator
762 : {
763 : public:
764 0 : static DeltaAccumulator* GetInstance()
765 : {
766 0 : if (!sInstance) {
767 0 : sInstance = new DeltaAccumulator;
768 : }
769 0 : return sInstance;
770 : }
771 :
772 0 : static void Shutdown()
773 : {
774 0 : delete sInstance;
775 0 : sInstance = nullptr;
776 0 : }
777 :
778 0 : bool IsInTransaction() { return mHandlingDeltaMode != UINT32_MAX; }
779 :
780 : /**
781 : * InitLineOrPageDelta() stores pixel delta values of WidgetWheelEvents
782 : * which are caused if it's needed. And if the accumulated delta becomes a
783 : * line height, sets lineOrPageDeltaX and lineOrPageDeltaY automatically.
784 : */
785 : void InitLineOrPageDelta(nsIFrame* aTargetFrame,
786 : EventStateManager* aESM,
787 : WidgetWheelEvent* aEvent);
788 :
789 : /**
790 : * Reset() resets all members.
791 : */
792 : void Reset();
793 :
794 : /**
795 : * ComputeScrollAmountForDefaultAction() computes the default action's
796 : * scroll amount in device pixels with mPendingScrollAmount*.
797 : */
798 : nsIntPoint ComputeScrollAmountForDefaultAction(
799 : WidgetWheelEvent* aEvent,
800 : const nsIntSize& aScrollAmountInDevPixels);
801 :
802 : private:
803 0 : DeltaAccumulator() :
804 : mX(0.0), mY(0.0), mPendingScrollAmountX(0.0), mPendingScrollAmountY(0.0),
805 0 : mHandlingDeltaMode(UINT32_MAX), mIsNoLineOrPageDeltaDevice(false)
806 : {
807 0 : }
808 :
809 : double mX;
810 : double mY;
811 :
812 : // When default action of a wheel event is scroll but some delta values
813 : // are ignored because the computed amount values are not integer, the
814 : // fractional values are saved by these members.
815 : double mPendingScrollAmountX;
816 : double mPendingScrollAmountY;
817 :
818 : TimeStamp mLastTime;
819 :
820 : uint32_t mHandlingDeltaMode;
821 : bool mIsNoLineOrPageDeltaDevice;
822 :
823 : static DeltaAccumulator* sInstance;
824 : };
825 :
826 : // end mousewheel functions
827 :
828 : /*
829 : * When a touch gesture is about to start, this function determines what
830 : * kind of gesture interaction we will want to use, based on what is
831 : * underneath the initial touch point.
832 : * Currently it decides between panning (finger scrolling) or dragging
833 : * the target element, as well as the orientation to trigger panning and
834 : * display visual boundary feedback. The decision is stored back in aEvent.
835 : */
836 : void DecideGestureEvent(WidgetGestureNotifyEvent* aEvent,
837 : nsIFrame* targetFrame);
838 :
839 : // routines for the d&d gesture tracking state machine
840 : void BeginTrackingDragGesture(nsPresContext* aPresContext,
841 : WidgetMouseEvent* aDownEvent,
842 : nsIFrame* aDownFrame);
843 :
844 : friend class mozilla::dom::TabParent;
845 : void BeginTrackingRemoteDragGesture(nsIContent* aContent);
846 : void StopTrackingDragGesture();
847 : void GenerateDragGesture(nsPresContext* aPresContext,
848 : WidgetInputEvent* aEvent);
849 :
850 : /**
851 : * Determine which node the drag should be targeted at.
852 : * This is either the node clicked when there is a selection, or, for HTML,
853 : * the element with a draggable property set to true.
854 : *
855 : * aSelectionTarget - target to check for selection
856 : * aDataTransfer - data transfer object that will contain the data to drag
857 : * aSelection - [out] set to the selection to be dragged
858 : * aTargetNode - [out] the draggable node, or null if there isn't one
859 : */
860 : void DetermineDragTargetAndDefaultData(nsPIDOMWindowOuter* aWindow,
861 : nsIContent* aSelectionTarget,
862 : dom::DataTransfer* aDataTransfer,
863 : nsISelection** aSelection,
864 : nsIContent** aTargetNode);
865 :
866 : /*
867 : * Perform the default handling for the dragstart event and set up a
868 : * drag for aDataTransfer if it contains any data. Returns true if a drag has
869 : * started.
870 : *
871 : * aDragEvent - the dragstart event
872 : * aDataTransfer - the data transfer that holds the data to be dragged
873 : * aDragTarget - the target of the drag
874 : * aSelection - the selection to be dragged
875 : */
876 : bool DoDefaultDragStart(nsPresContext* aPresContext,
877 : WidgetDragEvent* aDragEvent,
878 : dom::DataTransfer* aDataTransfer,
879 : nsIContent* aDragTarget,
880 : nsISelection* aSelection);
881 :
882 8 : bool IsTrackingDragGesture ( ) const { return mGestureDownContent != nullptr; }
883 : /**
884 : * Set the fields of aEvent to reflect the mouse position and modifier keys
885 : * that were set when the user first pressed the mouse button (stored by
886 : * BeginTrackingDragGesture). aEvent->mWidget must be
887 : * mCurrentTarget->GetNearestWidget().
888 : */
889 : void FillInEventFromGestureDown(WidgetMouseEvent* aEvent);
890 :
891 : nsresult DoContentCommandEvent(WidgetContentCommandEvent* aEvent);
892 : nsresult DoContentCommandScrollEvent(WidgetContentCommandEvent* aEvent);
893 :
894 : dom::TabParent *GetCrossProcessTarget();
895 : bool IsTargetCrossProcess(WidgetGUIEvent* aEvent);
896 :
897 : /**
898 : * DispatchCrossProcessEvent() try to post aEvent to target remote process.
899 : * If you need to check if the event is posted to a remote process, you
900 : * can use aEvent->HasBeenPostedToRemoteProcess().
901 : */
902 : void DispatchCrossProcessEvent(WidgetEvent* aEvent,
903 : nsFrameLoader* aRemote,
904 : nsEventStatus *aStatus);
905 : /**
906 : * HandleCrossProcessEvent() may post aEvent to target remote processes.
907 : * When it succeeded to post the event to at least one remote process,
908 : * returns true. Otherwise, including the case not tried to dispatch to
909 : * post the event, returns false.
910 : * If you need to check if the event is posted to at least one remote
911 : * process, you can use aEvent->HasBeenPostedToRemoteProcess().
912 : */
913 : bool HandleCrossProcessEvent(WidgetEvent* aEvent,
914 : nsEventStatus* aStatus);
915 :
916 : void ReleaseCurrentIMEContentObserver();
917 :
918 : void HandleQueryContentEvent(WidgetQueryContentEvent* aEvent);
919 :
920 : private:
921 : static inline void DoStateChange(dom::Element* aElement,
922 : EventStates aState, bool aAddState);
923 : static inline void DoStateChange(nsIContent* aContent, EventStates aState,
924 : bool aAddState);
925 : static void UpdateAncestorState(nsIContent* aStartNode,
926 : nsIContent* aStopBefore,
927 : EventStates aState,
928 : bool aAddState);
929 : static void ResetLastOverForContent(const uint32_t& aIdx,
930 : RefPtr<OverOutElementsWrapper>& aChunk,
931 : nsIContent* aClosure);
932 :
933 : int32_t mLockCursor;
934 : bool mLastFrameConsumedSetCursor;
935 :
936 : // Last mouse event mRefPoint (the offset from the widget's origin in
937 : // device pixels) when mouse was locked, used to restore mouse position
938 : // after unlocking.
939 : static LayoutDeviceIntPoint sPreLockPoint;
940 :
941 : // Stores the mRefPoint of the last synthetic mouse move we dispatched
942 : // to re-center the mouse when we were pointer locked. If this is (-1,-1) it
943 : // means we've not recently dispatched a centering event. We use this to
944 : // detect when we receive the synth event, so we can cancel and not send it
945 : // to content.
946 : static LayoutDeviceIntPoint sSynthCenteringPoint;
947 :
948 : WeakFrame mCurrentTarget;
949 : nsCOMPtr<nsIContent> mCurrentTargetContent;
950 : static AutoWeakFrame sLastDragOverFrame;
951 :
952 : // Stores the mRefPoint (the offset from the widget's origin in device
953 : // pixels) of the last mouse event.
954 : static LayoutDeviceIntPoint sLastRefPoint;
955 :
956 : // member variables for the d&d gesture state machine
957 : LayoutDeviceIntPoint mGestureDownPoint; // screen coordinates
958 : // The content to use as target if we start a d&d (what we drag).
959 : nsCOMPtr<nsIContent> mGestureDownContent;
960 : // The content of the frame where the mouse-down event occurred. It's the same
961 : // as the target in most cases but not always - for example when dragging
962 : // an <area> of an image map this is the image. (bug 289667)
963 : nsCOMPtr<nsIContent> mGestureDownFrameOwner;
964 : // State of keys when the original gesture-down happened
965 : Modifiers mGestureModifiers;
966 : uint16_t mGestureDownButtons;
967 :
968 : nsCOMPtr<nsIContent> mLastLeftMouseDownContent;
969 : nsCOMPtr<nsIContent> mLastLeftMouseDownContentParent;
970 : nsCOMPtr<nsIContent> mLastMiddleMouseDownContent;
971 : nsCOMPtr<nsIContent> mLastMiddleMouseDownContentParent;
972 : nsCOMPtr<nsIContent> mLastRightMouseDownContent;
973 : nsCOMPtr<nsIContent> mLastRightMouseDownContentParent;
974 :
975 : nsCOMPtr<nsIContent> mActiveContent;
976 : nsCOMPtr<nsIContent> mHoverContent;
977 : static nsCOMPtr<nsIContent> sDragOverContent;
978 : nsCOMPtr<nsIContent> mURLTargetContent;
979 :
980 : nsPresContext* mPresContext; // Not refcnted
981 : nsCOMPtr<nsIDocument> mDocument; // Doesn't necessarily need to be owner
982 :
983 : RefPtr<IMEContentObserver> mIMEContentObserver;
984 :
985 : uint32_t mLClickCount;
986 : uint32_t mMClickCount;
987 : uint32_t mRClickCount;
988 :
989 : bool mInTouchDrag;
990 :
991 : bool m_haveShutdown;
992 :
993 : // Time at which we began handling user input. Reset to the epoch
994 : // once we have finished handling user input.
995 : static TimeStamp sHandlingInputStart;
996 :
997 : // Time at which we began handling the latest user input. Not reset
998 : // at the end of the input.
999 : static TimeStamp sLatestUserInputStart;
1000 :
1001 : RefPtr<OverOutElementsWrapper> mMouseEnterLeaveHelper;
1002 : nsRefPtrHashtable<nsUint32HashKey, OverOutElementsWrapper> mPointersEnterLeaveHelper;
1003 :
1004 : public:
1005 : static nsresult UpdateUserActivityTimer(void);
1006 : // Array for accesskey support
1007 : nsCOMArray<nsIContent> mAccessKeys;
1008 :
1009 : // The number of user inputs handled since process start. This
1010 : // includes anything that is initiated by user, with the exception
1011 : // of page load events or mouse over events.
1012 : static uint64_t sUserInputCounter;
1013 :
1014 : // The current depth of user inputs. This includes anything that is
1015 : // initiated by user, with the exception of page load events or
1016 : // mouse over events. Incremented whenever we start handling a user
1017 : // input, decremented when we have finished handling a user
1018 : // input. This depth is *not* reset in case of nested event loops.
1019 : static int32_t sUserInputEventDepth;
1020 :
1021 : static bool sNormalLMouseEventInProcess;
1022 :
1023 : static EventStateManager* sActiveESM;
1024 :
1025 : static void ClearGlobalActiveContent(EventStateManager* aClearer);
1026 :
1027 : // Functions used for click hold context menus
1028 : nsCOMPtr<nsITimer> mClickHoldTimer;
1029 : void CreateClickHoldTimer(nsPresContext* aPresContext,
1030 : nsIFrame* aDownFrame,
1031 : WidgetGUIEvent* aMouseDownEvent);
1032 : void KillClickHoldTimer();
1033 : void FireContextClick();
1034 :
1035 : static void SetPointerLock(nsIWidget* aWidget, nsIContent* aElement) ;
1036 : static void sClickHoldCallback ( nsITimer* aTimer, void* aESM ) ;
1037 : };
1038 :
1039 : /**
1040 : * This class is used while processing real user input. During this time, popups
1041 : * are allowed. For mousedown events, mouse capturing is also permitted.
1042 : */
1043 : class AutoHandlingUserInputStatePusher
1044 : {
1045 : public:
1046 : AutoHandlingUserInputStatePusher(bool aIsHandlingUserInput,
1047 : WidgetEvent* aEvent,
1048 : nsIDocument* aDocument);
1049 : ~AutoHandlingUserInputStatePusher();
1050 :
1051 : protected:
1052 : bool mIsHandlingUserInput;
1053 : bool mIsMouseDown;
1054 : bool mResetFMMouseButtonHandlingState;
1055 :
1056 : nsCOMPtr<nsIDocument> mMouseButtonEventHandlingDocument;
1057 :
1058 : private:
1059 : // Hide so that this class can only be stack-allocated
1060 : static void* operator new(size_t /*size*/) CPP_THROW_NEW { return nullptr; }
1061 : static void operator delete(void* /*memory*/) {}
1062 : };
1063 :
1064 : } // namespace mozilla
1065 :
1066 : // Click and double-click events need to be handled even for content that
1067 : // has no frame. This is required for Web compatibility.
1068 : #define NS_EVENT_NEEDS_FRAME(event) \
1069 : (!(event)->HasPluginActivationEventMessage() && \
1070 : (event)->mMessage != eMouseClick && \
1071 : (event)->mMessage != eMouseDoubleClick && \
1072 : (event)->mMessage != eMouseAuxClick)
1073 :
1074 : #endif // mozilla_EventStateManager_h_
|