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 #include "mozilla/layers/IAPZCTreeManager.h"
8 
9 #include "gfxPrefs.h"                       // for gfxPrefs
10 #include "InputData.h"                      // for InputData, etc
11 #include "mozilla/EventStateManager.h"      // for WheelPrefs
12 #include "mozilla/layers/APZThreadUtils.h"  // for AssertOnControllerThread, etc
13 #include "mozilla/MouseEvents.h"            // for WidgetMouseEvent
14 #include "mozilla/TextEvents.h"             // for WidgetKeyboardEvent
15 #include "mozilla/TouchEvents.h"            // for WidgetTouchEvent
16 #include "mozilla/WheelHandlingHelper.h"    // for AutoWheelDeltaAdjuster
17 
18 namespace mozilla {
19 namespace layers {
20 
WillHandleMouseEvent(const WidgetMouseEventBase & aEvent)21 static bool WillHandleMouseEvent(const WidgetMouseEventBase& aEvent) {
22   return aEvent.mMessage == eMouseMove || aEvent.mMessage == eMouseDown ||
23          aEvent.mMessage == eMouseUp || aEvent.mMessage == eDragEnd ||
24          (gfxPrefs::TestEventsAsyncEnabled() &&
25           aEvent.mMessage == eMouseHitTest);
26 }
27 
WillHandleWheelEvent(WidgetWheelEvent * aEvent)28 /* static */ bool IAPZCTreeManager::WillHandleWheelEvent(
29     WidgetWheelEvent* aEvent) {
30   return EventStateManager::WheelEventIsScrollAction(aEvent) &&
31          (aEvent->mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE ||
32           aEvent->mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL ||
33           aEvent->mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_PAGE);
34 }
35 
ReceiveInputEvent(WidgetInputEvent & aEvent,ScrollableLayerGuid * aOutTargetGuid,uint64_t * aOutInputBlockId)36 nsEventStatus IAPZCTreeManager::ReceiveInputEvent(
37     WidgetInputEvent& aEvent, ScrollableLayerGuid* aOutTargetGuid,
38     uint64_t* aOutInputBlockId) {
39   APZThreadUtils::AssertOnControllerThread();
40 
41   // Initialize aOutInputBlockId to a sane value, and then later we overwrite
42   // it if the input event goes into a block.
43   if (aOutInputBlockId) {
44     *aOutInputBlockId = 0;
45   }
46 
47   switch (aEvent.mClass) {
48     case eMouseEventClass:
49     case eDragEventClass: {
50       WidgetMouseEvent& mouseEvent = *aEvent.AsMouseEvent();
51 
52       // Note, we call this before having transformed the reference point.
53       if (mouseEvent.IsReal()) {
54         UpdateWheelTransaction(mouseEvent.mRefPoint, mouseEvent.mMessage);
55       }
56 
57       if (WillHandleMouseEvent(mouseEvent)) {
58         MouseInput input(mouseEvent);
59         input.mOrigin =
60             ScreenPoint(mouseEvent.mRefPoint.x, mouseEvent.mRefPoint.y);
61 
62         nsEventStatus status =
63             ReceiveInputEvent(input, aOutTargetGuid, aOutInputBlockId);
64 
65         mouseEvent.mRefPoint.x = input.mOrigin.x;
66         mouseEvent.mRefPoint.y = input.mOrigin.y;
67         mouseEvent.mFlags.mHandledByAPZ = input.mHandledByAPZ;
68         mouseEvent.mFocusSequenceNumber = input.mFocusSequenceNumber;
69         return status;
70       }
71 
72       ProcessUnhandledEvent(&mouseEvent.mRefPoint, aOutTargetGuid,
73                             &aEvent.mFocusSequenceNumber);
74       return nsEventStatus_eIgnore;
75     }
76     case eTouchEventClass: {
77       WidgetTouchEvent& touchEvent = *aEvent.AsTouchEvent();
78       MultiTouchInput touchInput(touchEvent);
79       nsEventStatus result =
80           ReceiveInputEvent(touchInput, aOutTargetGuid, aOutInputBlockId);
81       // touchInput was modified in-place to possibly remove some
82       // touch points (if we are overscrolled), and the coordinates were
83       // modified using the APZ untransform. We need to copy these changes
84       // back into the WidgetInputEvent.
85       touchEvent.mTouches.Clear();
86       touchEvent.mTouches.SetCapacity(touchInput.mTouches.Length());
87       for (size_t i = 0; i < touchInput.mTouches.Length(); i++) {
88         *touchEvent.mTouches.AppendElement() =
89             touchInput.mTouches[i].ToNewDOMTouch();
90       }
91       touchEvent.mFlags.mHandledByAPZ = touchInput.mHandledByAPZ;
92       touchEvent.mFocusSequenceNumber = touchInput.mFocusSequenceNumber;
93       return result;
94     }
95     case eWheelEventClass: {
96       WidgetWheelEvent& wheelEvent = *aEvent.AsWheelEvent();
97 
98       if (WillHandleWheelEvent(&wheelEvent)) {
99         ScrollWheelInput::ScrollMode scrollMode =
100             ScrollWheelInput::SCROLLMODE_INSTANT;
101         if (gfxPrefs::SmoothScrollEnabled() &&
102             ((wheelEvent.mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE &&
103               gfxPrefs::WheelSmoothScrollEnabled()) ||
104              (wheelEvent.mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_PAGE &&
105               gfxPrefs::PageSmoothScrollEnabled()))) {
106           scrollMode = ScrollWheelInput::SCROLLMODE_SMOOTH;
107         }
108 
109         // AutoWheelDeltaAdjuster may adjust the delta values for default
110         // action hander.  The delta values will be restored automatically
111         // when its instance is destroyed.
112         AutoWheelDeltaAdjuster adjuster(wheelEvent);
113 
114         // If the wheel event becomes no-op event, don't handle it as scroll.
115         if (wheelEvent.mDeltaX || wheelEvent.mDeltaY) {
116           ScreenPoint origin(wheelEvent.mRefPoint.x, wheelEvent.mRefPoint.y);
117           ScrollWheelInput input(
118               wheelEvent.mTime, wheelEvent.mTimeStamp, 0, scrollMode,
119               ScrollWheelInput::DeltaTypeForDeltaMode(wheelEvent.mDeltaMode),
120               origin, wheelEvent.mDeltaX, wheelEvent.mDeltaY,
121               wheelEvent.mAllowToOverrideSystemScrollSpeed);
122 
123           // We add the user multiplier as a separate field, rather than
124           // premultiplying it, because if the input is converted back to a
125           // WidgetWheelEvent, then EventStateManager would apply the delta a
126           // second time. We could in theory work around this by asking ESM to
127           // customize the event much sooner, and then save the
128           // "mCustomizedByUserPrefs" bit on ScrollWheelInput - but for now,
129           // this seems easier.
130           EventStateManager::GetUserPrefsForWheelEvent(
131               &wheelEvent, &input.mUserDeltaMultiplierX,
132               &input.mUserDeltaMultiplierY);
133 
134           nsEventStatus status =
135               ReceiveInputEvent(input, aOutTargetGuid, aOutInputBlockId);
136           wheelEvent.mRefPoint.x = input.mOrigin.x;
137           wheelEvent.mRefPoint.y = input.mOrigin.y;
138           wheelEvent.mFlags.mHandledByAPZ = input.mHandledByAPZ;
139           wheelEvent.mFocusSequenceNumber = input.mFocusSequenceNumber;
140           return status;
141         }
142       }
143 
144       UpdateWheelTransaction(aEvent.mRefPoint, aEvent.mMessage);
145       ProcessUnhandledEvent(&aEvent.mRefPoint, aOutTargetGuid,
146                             &aEvent.mFocusSequenceNumber);
147       return nsEventStatus_eIgnore;
148     }
149     case eKeyboardEventClass: {
150       WidgetKeyboardEvent& keyboardEvent = *aEvent.AsKeyboardEvent();
151 
152       KeyboardInput input(keyboardEvent);
153 
154       nsEventStatus status =
155           ReceiveInputEvent(input, aOutTargetGuid, aOutInputBlockId);
156 
157       keyboardEvent.mFlags.mHandledByAPZ = input.mHandledByAPZ;
158       keyboardEvent.mFocusSequenceNumber = input.mFocusSequenceNumber;
159       return status;
160     }
161     default: {
162       UpdateWheelTransaction(aEvent.mRefPoint, aEvent.mMessage);
163       ProcessUnhandledEvent(&aEvent.mRefPoint, aOutTargetGuid,
164                             &aEvent.mFocusSequenceNumber);
165       return nsEventStatus_eIgnore;
166     }
167   }
168 
169   MOZ_ASSERT_UNREACHABLE("Invalid WidgetInputEvent type.");
170   return nsEventStatus_eConsumeNoDefault;
171 }
172 
173 }  // namespace layers
174 }  // namespace mozilla
175