Bug 1885602 - Part 5: Implement navigating to the SUMO help topic from the menu heade...
[gecko.git] / dom / events / WheelEvent.cpp
blob6b5882662744451e95542d8446b8d6b508303ce5
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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/MouseEventBinding.h"
8 #include "mozilla/dom/WheelEvent.h"
9 #include "mozilla/MouseEvents.h"
10 #include "prtime.h"
12 namespace mozilla::dom {
14 WheelEvent::WheelEvent(EventTarget* aOwner, nsPresContext* aPresContext,
15 WidgetWheelEvent* aWheelEvent)
16 : MouseEvent(aOwner, aPresContext,
17 aWheelEvent
18 ? aWheelEvent
19 : new WidgetWheelEvent(false, eVoidEvent, nullptr)),
20 mAppUnitsPerDevPixel(0) {
21 if (aWheelEvent) {
22 mEventIsInternal = false;
23 // If the delta mode is pixel, the WidgetWheelEvent's delta values are in
24 // device pixels. However, JS contents need the delta values in CSS pixels.
25 // We should store the value of mAppUnitsPerDevPixel here because
26 // it might be changed by changing zoom or something.
27 if (aWheelEvent->mDeltaMode == WheelEvent_Binding::DOM_DELTA_PIXEL) {
28 mAppUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel();
30 } else {
31 mEventIsInternal = true;
32 mEvent->mRefPoint = LayoutDeviceIntPoint(0, 0);
33 mEvent->AsWheelEvent()->mInputSource =
34 MouseEvent_Binding::MOZ_SOURCE_UNKNOWN;
38 void WheelEvent::InitWheelEvent(
39 const nsAString& aType, bool aCanBubble, bool aCancelable,
40 nsGlobalWindowInner* aView, int32_t aDetail, int32_t aScreenX,
41 int32_t aScreenY, int32_t aClientX, int32_t aClientY, uint16_t aButton,
42 EventTarget* aRelatedTarget, const nsAString& aModifiersList,
43 double aDeltaX, double aDeltaY, double aDeltaZ, uint32_t aDeltaMode) {
44 NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
46 MouseEvent::InitMouseEvent(aType, aCanBubble, aCancelable, aView, aDetail,
47 aScreenX, aScreenY, aClientX, aClientY, aButton,
48 aRelatedTarget, aModifiersList);
50 WidgetWheelEvent* wheelEvent = mEvent->AsWheelEvent();
51 // When specified by the caller (for JS-created events), don't mess with the
52 // delta mode.
53 wheelEvent->mDeltaModeCheckingState =
54 WidgetWheelEvent::DeltaModeCheckingState::Checked;
55 wheelEvent->mDeltaX = aDeltaX;
56 wheelEvent->mDeltaY = aDeltaY;
57 wheelEvent->mDeltaZ = aDeltaZ;
58 wheelEvent->mDeltaMode = aDeltaMode;
59 wheelEvent->mAllowToOverrideSystemScrollSpeed = false;
62 int32_t WheelEvent::WheelDeltaX(CallerType aCallerType) {
63 WidgetWheelEvent* ev = mEvent->AsWheelEvent();
64 if (ev->mWheelTicksX != 0.0) {
65 return int32_t(-ev->mWheelTicksX * kNativeTicksToWheelDelta);
67 if (IsTrusted()) {
68 // We always return pixels regardless of the checking-state.
69 double pixelDelta =
70 ev->mDeltaMode == WheelEvent_Binding::DOM_DELTA_PIXEL
71 ? CSSCoord(DevToCssPixels(ev->OverriddenDeltaX()))
72 : ev->OverriddenDeltaX() *
73 CSSPixel::FromAppUnits(ev->mScrollAmount.width).Rounded();
74 return int32_t(-std::round(pixelDelta * kTrustedDeltaToWheelDelta));
76 return int32_t(-std::round(DeltaX(aCallerType))); // This matches Safari.
79 int32_t WheelEvent::WheelDeltaY(CallerType aCallerType) {
80 WidgetWheelEvent* ev = mEvent->AsWheelEvent();
81 if (ev->mWheelTicksY != 0.0) {
82 return int32_t(-ev->mWheelTicksY * kNativeTicksToWheelDelta);
85 if (IsTrusted()) {
86 double pixelDelta =
87 ev->mDeltaMode == WheelEvent_Binding::DOM_DELTA_PIXEL
88 ? CSSCoord(DevToCssPixels(ev->OverriddenDeltaY()))
89 : ev->OverriddenDeltaY() *
90 CSSPixel::FromAppUnits(ev->mScrollAmount.height).Rounded();
91 return int32_t(-std::round(pixelDelta * kTrustedDeltaToWheelDelta));
93 return int32_t(-std::round(DeltaY(aCallerType))); // This matches Safari.
96 double WheelEvent::ToWebExposedDelta(WidgetWheelEvent& aWidgetEvent,
97 double aDelta, nscoord aLineOrPageAmount,
98 CallerType aCallerType) {
99 using DeltaModeCheckingState = WidgetWheelEvent::DeltaModeCheckingState;
100 if (aCallerType != CallerType::System) {
101 if (aWidgetEvent.mDeltaModeCheckingState ==
102 DeltaModeCheckingState::Unknown) {
103 aWidgetEvent.mDeltaModeCheckingState = DeltaModeCheckingState::Unchecked;
105 if (aWidgetEvent.mDeltaModeCheckingState ==
106 DeltaModeCheckingState::Unchecked &&
107 aWidgetEvent.mDeltaMode == WheelEvent_Binding::DOM_DELTA_LINE) {
108 return aDelta * CSSPixel::FromAppUnits(aLineOrPageAmount).Rounded();
111 return DevToCssPixels(aDelta);
114 double WheelEvent::DeltaX(CallerType aCallerType) {
115 WidgetWheelEvent* ev = mEvent->AsWheelEvent();
116 return ToWebExposedDelta(*ev, ev->OverriddenDeltaX(), ev->mScrollAmount.width,
117 aCallerType);
120 double WheelEvent::DeltaY(CallerType aCallerType) {
121 WidgetWheelEvent* ev = mEvent->AsWheelEvent();
122 return ToWebExposedDelta(*ev, ev->OverriddenDeltaY(),
123 ev->mScrollAmount.height, aCallerType);
126 double WheelEvent::DeltaZ(CallerType aCallerType) {
127 WidgetWheelEvent* ev = mEvent->AsWheelEvent();
128 // XXX Unclear what scroll amount we should use for deltaZ...
129 auto amount = std::max(ev->mScrollAmount.width, ev->mScrollAmount.height);
130 return ToWebExposedDelta(*ev, ev->mDeltaZ, amount, aCallerType);
133 uint32_t WheelEvent::DeltaMode(CallerType aCallerType) {
134 using DeltaModeCheckingState = WidgetWheelEvent::DeltaModeCheckingState;
136 WidgetWheelEvent* ev = mEvent->AsWheelEvent();
137 uint32_t mode = ev->mDeltaMode;
138 if (aCallerType != CallerType::System) {
139 if (ev->mDeltaModeCheckingState == DeltaModeCheckingState::Unknown) {
140 ev->mDeltaModeCheckingState = DeltaModeCheckingState::Checked;
141 } else if (ev->mDeltaModeCheckingState ==
142 DeltaModeCheckingState::Unchecked &&
143 mode == WheelEvent_Binding::DOM_DELTA_LINE) {
144 return WheelEvent_Binding::DOM_DELTA_PIXEL;
148 return mode;
151 already_AddRefed<WheelEvent> WheelEvent::Constructor(
152 const GlobalObject& aGlobal, const nsAString& aType,
153 const WheelEventInit& aParam) {
154 nsCOMPtr<EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
155 RefPtr<WheelEvent> e = new WheelEvent(t, nullptr, nullptr);
156 bool trusted = e->Init(t);
157 e->InitWheelEvent(aType, aParam.mBubbles, aParam.mCancelable, aParam.mView,
158 aParam.mDetail, aParam.mScreenX, aParam.mScreenY,
159 aParam.mClientX, aParam.mClientY, aParam.mButton,
160 aParam.mRelatedTarget, u""_ns, aParam.mDeltaX,
161 aParam.mDeltaY, aParam.mDeltaZ, aParam.mDeltaMode);
162 e->InitializeExtraMouseEventDictionaryMembers(aParam);
163 e->SetTrusted(trusted);
164 e->SetComposed(aParam.mComposed);
165 return e.forget();
168 } // namespace mozilla::dom
170 using namespace mozilla;
171 using namespace mozilla::dom;
173 already_AddRefed<WheelEvent> NS_NewDOMWheelEvent(EventTarget* aOwner,
174 nsPresContext* aPresContext,
175 WidgetWheelEvent* aEvent) {
176 RefPtr<WheelEvent> it = new WheelEvent(aOwner, aPresContext, aEvent);
177 return it.forget();