Bug 1850713: remove duplicated setting of early hint preloader id in `ScriptLoader...
[gecko.git] / dom / events / UIEvent.cpp
blobb108ebb93853dfed613f4ffb5cb1cb3417a70bdd
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/. */
7 #include "base/basictypes.h"
8 #include "ipc/IPCMessageUtils.h"
9 #include "ipc/IPCMessageUtilsSpecializations.h"
10 #include "mozilla/dom/UIEvent.h"
11 #include "mozilla/ArrayUtils.h"
12 #include "mozilla/Assertions.h"
13 #include "mozilla/ContentEvents.h"
14 #include "mozilla/EventStateManager.h"
15 #include "mozilla/PointerLockManager.h"
16 #include "mozilla/PresShell.h"
17 #include "mozilla/TextEvents.h"
18 #include "nsCOMPtr.h"
19 #include "nsContentUtils.h"
20 #include "nsIContent.h"
21 #include "nsIInterfaceRequestorUtils.h"
22 #include "nsIDocShell.h"
23 #include "nsIFrame.h"
24 #include "nsLayoutUtils.h"
25 #include "prtime.h"
27 namespace mozilla::dom {
29 UIEvent::UIEvent(EventTarget* aOwner, nsPresContext* aPresContext,
30 WidgetGUIEvent* aEvent)
31 : Event(aOwner, aPresContext,
32 aEvent ? aEvent : new InternalUIEvent(false, eVoidEvent, nullptr)),
33 mDefaultClientPoint(0, 0),
34 mLayerPoint(0, 0),
35 mPagePoint(0, 0),
36 mMovementPoint(0, 0),
37 mIsPointerLocked(PointerLockManager::IsLocked()),
38 mLastClientPoint(EventStateManager::sLastClientPoint) {
39 if (aEvent) {
40 mEventIsInternal = false;
41 } else {
42 mEventIsInternal = true;
45 // Fill mDetail and mView according to the mEvent (widget-generated
46 // event) we've got
47 switch (mEvent->mClass) {
48 case eUIEventClass: {
49 mDetail = mEvent->AsUIEvent()->mDetail;
50 break;
53 case eScrollPortEventClass: {
54 InternalScrollPortEvent* scrollEvent = mEvent->AsScrollPortEvent();
55 mDetail = static_cast<int32_t>(scrollEvent->mOrient);
56 break;
59 default:
60 mDetail = 0;
61 break;
64 mView = nullptr;
65 if (mPresContext) {
66 nsIDocShell* docShell = mPresContext->GetDocShell();
67 if (docShell) {
68 mView = docShell->GetWindow();
73 // static
74 already_AddRefed<UIEvent> UIEvent::Constructor(const GlobalObject& aGlobal,
75 const nsAString& aType,
76 const UIEventInit& aParam) {
77 nsCOMPtr<EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
78 RefPtr<UIEvent> e = new UIEvent(t, nullptr, nullptr);
79 bool trusted = e->Init(t);
80 e->InitUIEvent(aType, aParam.mBubbles, aParam.mCancelable, aParam.mView,
81 aParam.mDetail);
82 e->SetTrusted(trusted);
83 e->SetComposed(aParam.mComposed);
84 return e.forget();
87 NS_IMPL_CYCLE_COLLECTION_INHERITED(UIEvent, Event, mView)
89 NS_IMPL_ADDREF_INHERITED(UIEvent, Event)
90 NS_IMPL_RELEASE_INHERITED(UIEvent, Event)
92 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(UIEvent)
93 NS_INTERFACE_MAP_END_INHERITING(Event)
95 static nsIntPoint DevPixelsToCSSPixels(const LayoutDeviceIntPoint& aPoint,
96 nsPresContext* aContext) {
97 return nsIntPoint(aContext->DevPixelsToIntCSSPixels(aPoint.x),
98 aContext->DevPixelsToIntCSSPixels(aPoint.y));
101 nsIntPoint UIEvent::GetMovementPoint() {
102 if (mEvent->mFlags.mIsPositionless) {
103 return nsIntPoint(0, 0);
106 if (mPrivateDataDuplicated || mEventIsInternal) {
107 return mMovementPoint;
110 if (!mEvent || !mEvent->AsGUIEvent()->mWidget ||
111 (mEvent->mMessage != eMouseMove && mEvent->mMessage != ePointerMove)) {
112 // Pointer Lock spec defines that movementX/Y must be zero for all mouse
113 // events except mousemove.
114 return nsIntPoint(0, 0);
117 // Calculate the delta between the last screen point and the current one.
118 nsIntPoint current = DevPixelsToCSSPixels(mEvent->mRefPoint, mPresContext);
119 nsIntPoint last = DevPixelsToCSSPixels(mEvent->mLastRefPoint, mPresContext);
120 return current - last;
123 void UIEvent::InitUIEvent(const nsAString& typeArg, bool canBubbleArg,
124 bool cancelableArg, nsGlobalWindowInner* viewArg,
125 int32_t detailArg) {
126 if (NS_WARN_IF(mEvent->mFlags.mIsBeingDispatched)) {
127 return;
130 Event::InitEvent(typeArg, canBubbleArg, cancelableArg);
132 mDetail = detailArg;
133 mView = viewArg ? viewArg->GetOuterWindow() : nullptr;
136 already_AddRefed<nsIContent> UIEvent::GetRangeParentContentAndOffset(
137 int32_t* aOffset) const {
138 if (NS_WARN_IF(!mPresContext)) {
139 return nullptr;
141 RefPtr<PresShell> presShell = mPresContext->GetPresShell();
142 if (NS_WARN_IF(!presShell)) {
143 return nullptr;
145 nsCOMPtr<nsIContent> container;
146 nsLayoutUtils::GetContainerAndOffsetAtEvent(
147 presShell, mEvent, getter_AddRefs(container), aOffset);
148 return container.forget();
151 int32_t UIEvent::RangeOffset() const {
152 if (NS_WARN_IF(!mPresContext)) {
153 return 0;
155 RefPtr<PresShell> presShell = mPresContext->GetPresShell();
156 if (NS_WARN_IF(!presShell)) {
157 return 0;
159 int32_t offset = 0;
160 nsLayoutUtils::GetContainerAndOffsetAtEvent(presShell, mEvent, nullptr,
161 &offset);
162 return offset;
165 nsIntPoint UIEvent::GetLayerPoint() const {
166 if (mEvent->mFlags.mIsPositionless) {
167 return nsIntPoint(0, 0);
170 if (!mEvent ||
171 (mEvent->mClass != eMouseEventClass &&
172 mEvent->mClass != eMouseScrollEventClass &&
173 mEvent->mClass != eWheelEventClass &&
174 mEvent->mClass != ePointerEventClass &&
175 mEvent->mClass != eTouchEventClass &&
176 mEvent->mClass != eDragEventClass &&
177 mEvent->mClass != eSimpleGestureEventClass) ||
178 !mPresContext || mEventIsInternal) {
179 return mLayerPoint;
181 // XXX I'm not really sure this is correct; it's my best shot, though
182 nsIFrame* targetFrame = mPresContext->EventStateManager()->GetEventTarget();
183 if (!targetFrame) return mLayerPoint;
184 nsIFrame* layer = nsLayoutUtils::GetClosestLayer(targetFrame);
185 nsPoint pt(
186 nsLayoutUtils::GetEventCoordinatesRelativeTo(mEvent, RelativeTo{layer}));
187 return nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
188 nsPresContext::AppUnitsToIntCSSPixels(pt.y));
191 void UIEvent::DuplicatePrivateData() {
192 mDefaultClientPoint = Event::GetClientCoords(
193 mPresContext, mEvent, mEvent->mRefPoint, mDefaultClientPoint);
194 mMovementPoint = GetMovementPoint();
195 mLayerPoint = GetLayerPoint();
196 mPagePoint = Event::GetPageCoords(mPresContext, mEvent, mEvent->mRefPoint,
197 mDefaultClientPoint);
198 // GetScreenPoint converts mEvent->mRefPoint to right coordinates.
199 CSSIntPoint screenPoint =
200 Event::GetScreenCoords(mPresContext, mEvent, mEvent->mRefPoint)
201 .valueOr(CSSIntPoint{0, 0});
203 Event::DuplicatePrivateData();
205 CSSToLayoutDeviceScale scale = mPresContext
206 ? mPresContext->CSSToDevPixelScale()
207 : CSSToLayoutDeviceScale(1);
208 mEvent->mRefPoint = RoundedToInt(screenPoint * scale);
211 void UIEvent::Serialize(IPC::MessageWriter* aWriter,
212 bool aSerializeInterfaceType) {
213 if (aSerializeInterfaceType) {
214 IPC::WriteParam(aWriter, u"uievent"_ns);
217 Event::Serialize(aWriter, false);
219 IPC::WriteParam(aWriter, Detail());
222 bool UIEvent::Deserialize(IPC::MessageReader* aReader) {
223 NS_ENSURE_TRUE(Event::Deserialize(aReader), false);
224 NS_ENSURE_TRUE(IPC::ReadParam(aReader, &mDetail), false);
225 return true;
228 // XXX Following struct and array are used only in
229 // UIEvent::ComputeModifierState(), but if we define them in it,
230 // we fail to build on Mac at calling mozilla::ArrayLength().
231 struct ModifierPair {
232 Modifier modifier;
233 const char* name;
235 static const ModifierPair kPairs[] = {
236 // clang-format off
237 { MODIFIER_ALT, NS_DOM_KEYNAME_ALT },
238 { MODIFIER_ALTGRAPH, NS_DOM_KEYNAME_ALTGRAPH },
239 { MODIFIER_CAPSLOCK, NS_DOM_KEYNAME_CAPSLOCK },
240 { MODIFIER_CONTROL, NS_DOM_KEYNAME_CONTROL },
241 { MODIFIER_FN, NS_DOM_KEYNAME_FN },
242 { MODIFIER_FNLOCK, NS_DOM_KEYNAME_FNLOCK },
243 { MODIFIER_META, NS_DOM_KEYNAME_META },
244 { MODIFIER_NUMLOCK, NS_DOM_KEYNAME_NUMLOCK },
245 { MODIFIER_SCROLLLOCK, NS_DOM_KEYNAME_SCROLLLOCK },
246 { MODIFIER_SHIFT, NS_DOM_KEYNAME_SHIFT },
247 { MODIFIER_SYMBOL, NS_DOM_KEYNAME_SYMBOL },
248 { MODIFIER_SYMBOLLOCK, NS_DOM_KEYNAME_SYMBOLLOCK },
249 // clang-format on
252 // static
253 Modifiers UIEvent::ComputeModifierState(const nsAString& aModifiersList) {
254 if (aModifiersList.IsEmpty()) {
255 return 0;
258 // Be careful about the performance. If aModifiersList is too long,
259 // parsing it needs too long time.
260 // XXX Should we abort if aModifiersList is too long?
262 Modifiers modifiers = 0;
264 nsAString::const_iterator listStart, listEnd;
265 aModifiersList.BeginReading(listStart);
266 aModifiersList.EndReading(listEnd);
268 for (uint32_t i = 0; i < ArrayLength(kPairs); i++) {
269 nsAString::const_iterator start(listStart), end(listEnd);
270 if (!FindInReadable(NS_ConvertASCIItoUTF16(kPairs[i].name), start, end)) {
271 continue;
274 if ((start != listStart && !NS_IsAsciiWhitespace(*(--start))) ||
275 (end != listEnd && !NS_IsAsciiWhitespace(*(end)))) {
276 continue;
278 modifiers |= kPairs[i].modifier;
281 return modifiers;
284 bool UIEvent::GetModifierStateInternal(const nsAString& aKey) {
285 WidgetInputEvent* inputEvent = mEvent->AsInputEvent();
286 MOZ_ASSERT(inputEvent, "mEvent must be WidgetInputEvent or derived class");
287 return ((inputEvent->mModifiers & WidgetInputEvent::GetModifier(aKey)) != 0);
290 void UIEvent::InitModifiers(const EventModifierInit& aParam) {
291 if (NS_WARN_IF(!mEvent)) {
292 return;
294 WidgetInputEvent* inputEvent = mEvent->AsInputEvent();
295 MOZ_ASSERT(inputEvent,
296 "This method shouldn't be called if it doesn't have modifiers");
297 if (NS_WARN_IF(!inputEvent)) {
298 return;
301 inputEvent->mModifiers = MODIFIER_NONE;
303 #define SET_MODIFIER(aName, aValue) \
304 if (aParam.m##aName) { \
305 inputEvent->mModifiers |= aValue; \
308 SET_MODIFIER(CtrlKey, MODIFIER_CONTROL)
309 SET_MODIFIER(ShiftKey, MODIFIER_SHIFT)
310 SET_MODIFIER(AltKey, MODIFIER_ALT)
311 SET_MODIFIER(MetaKey, MODIFIER_META)
312 SET_MODIFIER(ModifierAltGraph, MODIFIER_ALTGRAPH)
313 SET_MODIFIER(ModifierCapsLock, MODIFIER_CAPSLOCK)
314 SET_MODIFIER(ModifierFn, MODIFIER_FN)
315 SET_MODIFIER(ModifierFnLock, MODIFIER_FNLOCK)
316 SET_MODIFIER(ModifierNumLock, MODIFIER_NUMLOCK)
317 SET_MODIFIER(ModifierScrollLock, MODIFIER_SCROLLLOCK)
318 SET_MODIFIER(ModifierSymbol, MODIFIER_SYMBOL)
319 SET_MODIFIER(ModifierSymbolLock, MODIFIER_SYMBOLLOCK)
321 #undef SET_MODIFIER
324 } // namespace mozilla::dom
326 using namespace mozilla;
327 using namespace mozilla::dom;
329 already_AddRefed<UIEvent> NS_NewDOMUIEvent(EventTarget* aOwner,
330 nsPresContext* aPresContext,
331 WidgetGUIEvent* aEvent) {
332 RefPtr<UIEvent> it = new UIEvent(aOwner, aPresContext, aEvent);
333 return it.forget();