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