Source code

Revision control

Other Tools

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/APZInputBridge.h"
8
9
#include "InputData.h" // for MouseInput, etc
10
#include "InputBlockState.h" // for InputBlockState
11
#include "mozilla/dom/WheelEventBinding.h" // for WheelEvent constants
12
#include "mozilla/EventStateManager.h" // for EventStateManager
13
#include "mozilla/layers/APZThreadUtils.h" // for AssertOnControllerThread, etc
14
#include "mozilla/MouseEvents.h" // for WidgetMouseEvent
15
#include "mozilla/StaticPrefs_apz.h"
16
#include "mozilla/StaticPrefs_general.h"
17
#include "mozilla/StaticPrefs_test.h"
18
#include "mozilla/TextEvents.h" // for WidgetKeyboardEvent
19
#include "mozilla/TouchEvents.h" // for WidgetTouchEvent
20
#include "mozilla/WheelHandlingHelper.h" // for WheelDeltaHorizontalizer,
21
// WheelDeltaAdjustmentStrategy
22
23
namespace mozilla {
24
namespace layers {
25
26
APZEventResult::APZEventResult()
27
: mStatus(nsEventStatus_eIgnore),
28
mInputBlockId(InputBlockState::NO_BLOCK_ID),
29
mHitRegionWithApzAwareListeners(false) {}
30
31
static bool WillHandleMouseEvent(const WidgetMouseEventBase& aEvent) {
32
return aEvent.mMessage == eMouseMove || aEvent.mMessage == eMouseDown ||
33
aEvent.mMessage == eMouseUp || aEvent.mMessage == eDragEnd ||
34
(StaticPrefs::test_events_async_enabled() &&
35
aEvent.mMessage == eMouseHitTest);
36
}
37
38
/* static */
39
Maybe<APZWheelAction> APZInputBridge::ActionForWheelEvent(
40
WidgetWheelEvent* aEvent) {
41
if (!(aEvent->mDeltaMode == dom::WheelEvent_Binding::DOM_DELTA_LINE ||
42
aEvent->mDeltaMode == dom::WheelEvent_Binding::DOM_DELTA_PIXEL ||
43
aEvent->mDeltaMode == dom::WheelEvent_Binding::DOM_DELTA_PAGE)) {
44
return Nothing();
45
}
46
return EventStateManager::APZWheelActionFor(aEvent);
47
}
48
49
APZEventResult APZInputBridge::ReceiveInputEvent(WidgetInputEvent& aEvent) {
50
APZThreadUtils::AssertOnControllerThread();
51
52
APZEventResult result;
53
54
switch (aEvent.mClass) {
55
case eMouseEventClass:
56
case eDragEventClass: {
57
WidgetMouseEvent& mouseEvent = *aEvent.AsMouseEvent();
58
59
// Note, we call this before having transformed the reference point.
60
if (mouseEvent.IsReal()) {
61
UpdateWheelTransaction(mouseEvent.mRefPoint, mouseEvent.mMessage);
62
}
63
64
// If zooming is enabled, mark the mouse event as "ignore root
65
// scroll frame". This ensures that the main-thread hit test the
66
// mouse event undergoes (in PositionedEventTargeting.cpp) uses
67
// the IGNORE_ROOT_SCROLL_FRAME flag, which is needed for correct
68
// hit testing in a zoomed-in or zoomed-out state.
69
// FIXME: bug 1525793 -- this may need to handle zooming or not on a
70
// per-document basis.
71
if (StaticPrefs::apz_allow_zooming()) {
72
mouseEvent.mIgnoreRootScrollFrame = true;
73
}
74
75
if (WillHandleMouseEvent(mouseEvent)) {
76
MouseInput input(mouseEvent);
77
input.mOrigin =
78
ScreenPoint(mouseEvent.mRefPoint.x, mouseEvent.mRefPoint.y);
79
80
result = ReceiveInputEvent(input);
81
82
mouseEvent.mRefPoint.x = input.mOrigin.x;
83
mouseEvent.mRefPoint.y = input.mOrigin.y;
84
mouseEvent.mFlags.mHandledByAPZ = input.mHandledByAPZ;
85
mouseEvent.mFocusSequenceNumber = input.mFocusSequenceNumber;
86
aEvent.mLayersId = input.mLayersId;
87
return result;
88
}
89
90
ProcessUnhandledEvent(&mouseEvent.mRefPoint, &result.mTargetGuid,
91
&aEvent.mFocusSequenceNumber, &aEvent.mLayersId);
92
return result;
93
}
94
case eTouchEventClass: {
95
WidgetTouchEvent& touchEvent = *aEvent.AsTouchEvent();
96
MultiTouchInput touchInput(touchEvent);
97
result = ReceiveInputEvent(touchInput);
98
// touchInput was modified in-place to possibly remove some
99
// touch points (if we are overscrolled), and the coordinates were
100
// modified using the APZ untransform. We need to copy these changes
101
// back into the WidgetInputEvent.
102
touchEvent.mTouches.Clear();
103
touchEvent.mTouches.SetCapacity(touchInput.mTouches.Length());
104
for (size_t i = 0; i < touchInput.mTouches.Length(); i++) {
105
*touchEvent.mTouches.AppendElement() =
106
touchInput.mTouches[i].ToNewDOMTouch();
107
}
108
touchEvent.mFlags.mHandledByAPZ = touchInput.mHandledByAPZ;
109
touchEvent.mFocusSequenceNumber = touchInput.mFocusSequenceNumber;
110
aEvent.mLayersId = touchInput.mLayersId;
111
return result;
112
}
113
case eWheelEventClass: {
114
WidgetWheelEvent& wheelEvent = *aEvent.AsWheelEvent();
115
116
if (Maybe<APZWheelAction> action = ActionForWheelEvent(&wheelEvent)) {
117
ScrollWheelInput::ScrollMode scrollMode =
118
ScrollWheelInput::SCROLLMODE_INSTANT;
119
if (StaticPrefs::general_smoothScroll() &&
120
((wheelEvent.mDeltaMode ==
121
dom::WheelEvent_Binding::DOM_DELTA_LINE &&
122
StaticPrefs::general_smoothScroll_mouseWheel()) ||
123
(wheelEvent.mDeltaMode ==
124
dom::WheelEvent_Binding::DOM_DELTA_PAGE &&
125
StaticPrefs::general_smoothScroll_pages()))) {
126
scrollMode = ScrollWheelInput::SCROLLMODE_SMOOTH;
127
}
128
129
WheelDeltaAdjustmentStrategy strategy =
130
EventStateManager::GetWheelDeltaAdjustmentStrategy(wheelEvent);
131
// Adjust the delta values of the wheel event if the current default
132
// action is to horizontalize scrolling. I.e., deltaY values are set to
133
// deltaX and deltaY and deltaZ values are set to 0.
134
// If horizontalized, the delta values will be restored and its overflow
135
// deltaX will become 0 when the WheelDeltaHorizontalizer instance is
136
// being destroyed.
137
WheelDeltaHorizontalizer horizontalizer(wheelEvent);
138
if (WheelDeltaAdjustmentStrategy::eHorizontalize == strategy) {
139
horizontalizer.Horizontalize();
140
}
141
142
// If the wheel event becomes no-op event, don't handle it as scroll.
143
if (wheelEvent.mDeltaX || wheelEvent.mDeltaY) {
144
ScreenPoint origin(wheelEvent.mRefPoint.x, wheelEvent.mRefPoint.y);
145
ScrollWheelInput input(
146
wheelEvent.mTime, wheelEvent.mTimeStamp, 0, scrollMode,
147
ScrollWheelInput::DeltaTypeForDeltaMode(wheelEvent.mDeltaMode),
148
origin, wheelEvent.mDeltaX, wheelEvent.mDeltaY,
149
wheelEvent.mAllowToOverrideSystemScrollSpeed, strategy);
150
input.mAPZAction = action.value();
151
152
// We add the user multiplier as a separate field, rather than
153
// premultiplying it, because if the input is converted back to a
154
// WidgetWheelEvent, then EventStateManager would apply the delta a
155
// second time. We could in theory work around this by asking ESM to
156
// customize the event much sooner, and then save the
157
// "mCustomizedByUserPrefs" bit on ScrollWheelInput - but for now,
158
// this seems easier.
159
EventStateManager::GetUserPrefsForWheelEvent(
160
&wheelEvent, &input.mUserDeltaMultiplierX,
161
&input.mUserDeltaMultiplierY);
162
163
result = ReceiveInputEvent(input);
164
wheelEvent.mRefPoint.x = input.mOrigin.x;
165
wheelEvent.mRefPoint.y = input.mOrigin.y;
166
wheelEvent.mFlags.mHandledByAPZ = input.mHandledByAPZ;
167
wheelEvent.mFocusSequenceNumber = input.mFocusSequenceNumber;
168
aEvent.mLayersId = input.mLayersId;
169
170
return result;
171
}
172
}
173
174
UpdateWheelTransaction(aEvent.mRefPoint, aEvent.mMessage);
175
ProcessUnhandledEvent(&aEvent.mRefPoint, &result.mTargetGuid,
176
&aEvent.mFocusSequenceNumber, &aEvent.mLayersId);
177
result.mStatus = nsEventStatus_eIgnore;
178
return result;
179
}
180
case eKeyboardEventClass: {
181
WidgetKeyboardEvent& keyboardEvent = *aEvent.AsKeyboardEvent();
182
183
KeyboardInput input(keyboardEvent);
184
185
result = ReceiveInputEvent(input);
186
187
keyboardEvent.mFlags.mHandledByAPZ = input.mHandledByAPZ;
188
keyboardEvent.mFocusSequenceNumber = input.mFocusSequenceNumber;
189
return result;
190
}
191
default: {
192
UpdateWheelTransaction(aEvent.mRefPoint, aEvent.mMessage);
193
ProcessUnhandledEvent(&aEvent.mRefPoint, &result.mTargetGuid,
194
&aEvent.mFocusSequenceNumber, &aEvent.mLayersId);
195
return result;
196
}
197
}
198
199
MOZ_ASSERT_UNREACHABLE("Invalid WidgetInputEvent type.");
200
result.mStatus = nsEventStatus_eConsumeNoDefault;
201
return result;
202
}
203
204
} // namespace layers
205
} // namespace mozilla