Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp
Warning:line 1940, column 11
Access to field 'mMessage' results in a dereference of a null pointer (loaded from variable 'mouseEvent')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name EventStateManager.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/events -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/events -resource-dir /usr/lib/llvm-18/lib/clang/18 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /var/lib/jenkins/workspace/firefox-scan-build/dom/events -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/events -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /var/lib/jenkins/workspace/firefox-scan-build/ipc/chromium/src -I /var/lib/jenkins/workspace/firefox-scan-build/docshell/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/html -I /var/lib/jenkins/workspace/firefox-scan-build/dom/storage -I /var/lib/jenkins/workspace/firefox-scan-build/dom/xml -I /var/lib/jenkins/workspace/firefox-scan-build/dom/xul -I /var/lib/jenkins/workspace/firefox-scan-build/js/xpconnect/wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/layout/forms -I /var/lib/jenkins/workspace/firefox-scan-build/layout/generic -I /var/lib/jenkins/workspace/firefox-scan-build/layout/xul -I /var/lib/jenkins/workspace/firefox-scan-build/layout/xul/tree -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -fdeprecated-macro -ferror-limit 19 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-07-30-004816-4182763-1 -x c++ /var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp
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 "EventStateManager.h"
8
9#include "mozilla/AsyncEventDispatcher.h"
10#include "mozilla/Attributes.h"
11#include "mozilla/EditorBase.h"
12#include "mozilla/EventDispatcher.h"
13#include "mozilla/EventForwards.h"
14#include "mozilla/Hal.h"
15#include "mozilla/HTMLEditor.h"
16#include "mozilla/IMEStateManager.h"
17#include "mozilla/Likely.h"
18#include "mozilla/FocusModel.h"
19#include "mozilla/MiscEvents.h"
20#include "mozilla/MathAlgorithms.h"
21#include "mozilla/MouseEvents.h"
22#include "mozilla/PointerLockManager.h"
23#include "mozilla/PresShell.h"
24#include "mozilla/ScopeExit.h"
25#include "mozilla/ScrollTypes.h"
26#include "mozilla/TextComposition.h"
27#include "mozilla/TextControlElement.h"
28#include "mozilla/TextEditor.h"
29#include "mozilla/TextEvents.h"
30#include "mozilla/TouchEvents.h"
31#include "mozilla/Telemetry.h"
32#include "mozilla/UniquePtr.h"
33#include "mozilla/dom/BrowserBridgeChild.h"
34#include "mozilla/dom/BrowsingContext.h"
35#include "mozilla/dom/CanonicalBrowsingContext.h"
36#include "mozilla/dom/ContentChild.h"
37#include "mozilla/dom/DOMIntersectionObserver.h"
38#include "mozilla/dom/DragEvent.h"
39#include "mozilla/dom/Event.h"
40#include "mozilla/dom/FrameLoaderBinding.h"
41#include "mozilla/dom/HTMLLabelElement.h"
42#include "mozilla/dom/HTMLInputElement.h"
43#include "mozilla/dom/MouseEventBinding.h"
44#include "mozilla/dom/BrowserChild.h"
45#include "mozilla/dom/PointerEventHandler.h"
46#include "mozilla/dom/UIEvent.h"
47#include "mozilla/dom/UIEventBinding.h"
48#include "mozilla/dom/UserActivation.h"
49#include "mozilla/dom/WheelEventBinding.h"
50#include "mozilla/glean/GleanMetrics.h"
51#include "mozilla/ScrollContainerFrame.h"
52#include "mozilla/StaticPrefs_accessibility.h"
53#include "mozilla/StaticPrefs_browser.h"
54#include "mozilla/StaticPrefs_dom.h"
55#include "mozilla/StaticPrefs_layout.h"
56#include "mozilla/StaticPrefs_mousewheel.h"
57#include "mozilla/StaticPrefs_ui.h"
58#include "mozilla/StaticPrefs_zoom.h"
59
60#include "ContentEventHandler.h"
61#include "IMEContentObserver.h"
62#include "WheelHandlingHelper.h"
63#include "RemoteDragStartData.h"
64
65#include "nsCommandParams.h"
66#include "nsCOMPtr.h"
67#include "nsCopySupport.h"
68#include "nsFocusManager.h"
69#include "nsGenericHTMLElement.h"
70#include "nsIClipboard.h"
71#include "nsIContent.h"
72#include "nsIContentInlines.h"
73#include "mozilla/dom/Document.h"
74#include "nsICookieJarSettings.h"
75#include "nsIFrame.h"
76#include "nsFrameLoaderOwner.h"
77#include "nsIWeakReferenceUtils.h"
78#include "nsIWidget.h"
79#include "nsLiteralString.h"
80#include "nsPresContext.h"
81#include "nsTArray.h"
82#include "nsGkAtoms.h"
83#include "nsIFormControl.h"
84#include "nsComboboxControlFrame.h"
85#include "nsIDOMXULControlElement.h"
86#include "nsNameSpaceManager.h"
87#include "nsIBaseWindow.h"
88#include "nsFrameSelection.h"
89#include "nsPIDOMWindow.h"
90#include "nsPIWindowRoot.h"
91#include "nsIWebNavigation.h"
92#include "nsIDocumentViewer.h"
93#include "nsFrameManager.h"
94#include "nsIBrowserChild.h"
95#include "nsMenuPopupFrame.h"
96
97#include "nsIObserverService.h"
98#include "nsIDocShell.h"
99
100#include "nsSubDocumentFrame.h"
101#include "nsLayoutUtils.h"
102#include "nsIInterfaceRequestorUtils.h"
103#include "nsUnicharUtils.h"
104#include "nsContentUtils.h"
105
106#include "imgIContainer.h"
107#include "nsIProperties.h"
108#include "nsISupportsPrimitives.h"
109
110#include "nsServiceManagerUtils.h"
111#include "nsITimer.h"
112#include "nsFontMetrics.h"
113#include "nsIDragService.h"
114#include "nsIDragSession.h"
115#include "mozilla/dom/DataTransfer.h"
116#include "nsContentAreaDragDrop.h"
117#include "nsTreeBodyFrame.h"
118#include "nsIController.h"
119#include "mozilla/Services.h"
120#include "mozilla/dom/ContentParent.h"
121#include "mozilla/dom/Record.h"
122#include "mozilla/dom/Selection.h"
123
124#include "mozilla/Preferences.h"
125#include "mozilla/LookAndFeel.h"
126#include "mozilla/ProfilerLabels.h"
127#include "Units.h"
128
129#ifdef XP_MACOSX
130# import <ApplicationServices/ApplicationServices.h>
131#endif
132
133namespace mozilla {
134
135using namespace dom;
136
137static const LayoutDeviceIntPoint kInvalidRefPoint =
138 LayoutDeviceIntPoint(-1, -1);
139
140static uint32_t gMouseOrKeyboardEventCounter = 0;
141static nsITimer* gUserInteractionTimer = nullptr;
142static nsITimerCallback* gUserInteractionTimerCallback = nullptr;
143
144static const double kCursorLoadingTimeout = 1000; // ms
145static AutoWeakFrame gLastCursorSourceFrame;
146static TimeStamp gLastCursorUpdateTime;
147static TimeStamp gTypingStartTime;
148static TimeStamp gTypingEndTime;
149static int32_t gTypingInteractionKeyPresses = 0;
150static dom::InteractionData gTypingInteraction = {};
151
152static inline int32_t RoundDown(double aDouble) {
153 return (aDouble > 0) ? static_cast<int32_t>(floor(aDouble))
154 : static_cast<int32_t>(ceil(aDouble));
155}
156
157static bool IsSelectingLink(nsIFrame* aTargetFrame) {
158 if (!aTargetFrame) {
159 return false;
160 }
161 const nsFrameSelection* frameSel = aTargetFrame->GetConstFrameSelection();
162 if (!frameSel || !frameSel->GetDragState()) {
163 return false;
164 }
165
166 if (!nsContentUtils::GetClosestLinkInFlatTree(aTargetFrame->GetContent())) {
167 return false;
168 }
169 return true;
170}
171
172static UniquePtr<WidgetMouseEvent> CreateMouseOrPointerWidgetEvent(
173 WidgetMouseEvent* aMouseEvent, EventMessage aMessage,
174 EventTarget* aRelatedTarget);
175
176/**
177 * Returns the common ancestor for mouseup purpose, given the
178 * current mouseup target and the previous mousedown target.
179 */
180static nsINode* GetCommonAncestorForMouseUp(
181 nsINode* aCurrentMouseUpTarget, nsINode* aLastMouseDownTarget,
182 Maybe<FormControlType>& aLastMouseDownInputControlType) {
183 if (!aCurrentMouseUpTarget || !aLastMouseDownTarget) {
184 return nullptr;
185 }
186
187 if (aCurrentMouseUpTarget == aLastMouseDownTarget) {
188 return aCurrentMouseUpTarget;
189 }
190
191 // Build the chain of parents
192 AutoTArray<nsINode*, 30> parents1;
193 do {
194 parents1.AppendElement(aCurrentMouseUpTarget);
195 aCurrentMouseUpTarget = aCurrentMouseUpTarget->GetFlattenedTreeParentNode();
196 } while (aCurrentMouseUpTarget);
197
198 AutoTArray<nsINode*, 30> parents2;
199 do {
200 parents2.AppendElement(aLastMouseDownTarget);
201 if (aLastMouseDownTarget == parents1.LastElement()) {
202 break;
203 }
204 aLastMouseDownTarget = aLastMouseDownTarget->GetFlattenedTreeParentNode();
205 } while (aLastMouseDownTarget);
206
207 // Find where the parent chain differs
208 uint32_t pos1 = parents1.Length();
209 uint32_t pos2 = parents2.Length();
210 nsINode* parent = nullptr;
211 for (uint32_t len = std::min(pos1, pos2); len > 0; --len) {
212 nsINode* child1 = parents1.ElementAt(--pos1);
213 nsINode* child2 = parents2.ElementAt(--pos2);
214 if (child1 != child2) {
215 break;
216 }
217
218 // If the input control type is different between mouseup and mousedown,
219 // this is not a valid click.
220 if (HTMLInputElement* input = HTMLInputElement::FromNodeOrNull(child1)) {
221 if (aLastMouseDownInputControlType.isSome() &&
222 aLastMouseDownInputControlType.ref() != input->ControlType()) {
223 break;
224 }
225 }
226 parent = child1;
227 }
228
229 return parent;
230}
231
232LazyLogModule sMouseBoundaryLog("MouseBoundaryEvents");
233LazyLogModule sPointerBoundaryLog("PointerBoundaryEvents");
234
235/******************************************************************/
236/* mozilla::UITimerCallback */
237/******************************************************************/
238
239class UITimerCallback final : public nsITimerCallback, public nsINamed {
240 public:
241 UITimerCallback() : mPreviousCount(0) {}
242 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
243 NS_DECL_NSITIMERCALLBACKvirtual nsresult Notify(nsITimer *timer) override; inline void
_ensure_GetName_exists(void) { static_assert(std::is_convertible
<decltype(this), nsINamed*>::value, "nsITimerCallback implementations must also implement nsINamed"
); }
244 NS_DECL_NSINAMEDvirtual nsresult GetName(nsACString& aName) override;
245 private:
246 ~UITimerCallback() = default;
247 uint32_t mPreviousCount;
248};
249
250NS_IMPL_ISUPPORTS(UITimerCallback, nsITimerCallback, nsINamed)MozExternalRefCountType UITimerCallback::AddRef(void) { static_assert
(!std::is_destructible_v<UITimerCallback>, "Reference-counted class "
"UITimerCallback" " should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
250; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("UITimerCallback" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("UITimerCallback" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"UITimerCallback\" != nullptr" " (" "Must specify a name" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"UITimerCallback\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 250; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("UITimerCallback" " not thread-safe"); nsrefcnt
count = ++mRefCnt; NS_LogAddRef((this), (count), ("UITimerCallback"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
UITimerCallback::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 250
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("UITimerCallback" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("UITimerCallback" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"UITimerCallback\" != nullptr" " (" "Must specify a name" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"UITimerCallback\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 250; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("UITimerCallback" " not thread-safe"); const
char* const nametmp = "UITimerCallback"; nsrefcnt count = --
mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count
== 0) { mRefCnt = 1; delete (this); return 0; } return count
; } nsresult UITimerCallback::QueryInterface(const nsIID&
aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<UITimerCallback, nsITimerCallback>, int32_t
( reinterpret_cast<char*>(static_cast<nsITimerCallback
*>((UITimerCallback*)0x1000)) - reinterpret_cast<char*>
((UITimerCallback*)0x1000))}, {&mozilla::detail::kImplementedIID
<UITimerCallback, nsINamed>, int32_t( reinterpret_cast<
char*>(static_cast<nsINamed*>((UITimerCallback*)0x1000
)) - reinterpret_cast<char*>((UITimerCallback*)0x1000))
}, {&mozilla::detail::kImplementedIID<UITimerCallback,
nsISupports>, int32_t(reinterpret_cast<char*>(static_cast
<nsISupports*>( static_cast<nsITimerCallback*>((UITimerCallback
*)0x1000))) - reinterpret_cast<char*>((UITimerCallback*
)0x1000))}, { nullptr, 0 } } ; static_assert((sizeof(table) /
sizeof(table[0])) > 1, "need at least 1 interface"); rv =
NS_TableDrivenQI(static_cast<void*>(this), aIID, aInstancePtr
, table); return rv; }
251
252// If aTimer is nullptr, this method always sends "user-interaction-inactive"
253// notification.
254NS_IMETHODIMPnsresult
255UITimerCallback::Notify(nsITimer* aTimer) {
256 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
257 if (!obs) return NS_ERROR_FAILURE;
258 if ((gMouseOrKeyboardEventCounter == mPreviousCount) || !aTimer) {
259 gMouseOrKeyboardEventCounter = 0;
260 obs->NotifyObservers(nullptr, "user-interaction-inactive", nullptr);
261 if (gUserInteractionTimer) {
262 gUserInteractionTimer->Cancel();
263 NS_RELEASE(gUserInteractionTimer)do { (gUserInteractionTimer)->Release(); (gUserInteractionTimer
) = 0; } while (0)
;
264 }
265 } else {
266 obs->NotifyObservers(nullptr, "user-interaction-active", nullptr);
267 EventStateManager::UpdateUserActivityTimer();
268
269 if (XRE_IsParentProcess()) {
270 hal::BatteryInformation batteryInfo;
271 hal::GetCurrentBatteryInformation(&batteryInfo);
272 glean::power_battery::percentage_when_user_active.AccumulateSingleSample(
273 uint64_t(batteryInfo.level() * 100));
274 }
275 }
276 mPreviousCount = gMouseOrKeyboardEventCounter;
277 return NS_OK;
278}
279
280NS_IMETHODIMPnsresult
281UITimerCallback::GetName(nsACString& aName) {
282 aName.AssignLiteral("UITimerCallback_timer");
283 return NS_OK;
284}
285
286/******************************************************************/
287/* mozilla::OverOutElementsWrapper */
288/******************************************************************/
289
290NS_IMPL_CYCLE_COLLECTION(OverOutElementsWrapper, mDeepestEnterEventTarget,OverOutElementsWrapper::cycleCollection OverOutElementsWrapper
::_cycleCollectorGlobal; void OverOutElementsWrapper::cycleCollection
::Unlink(void* p) { OverOutElementsWrapper* tmp = DowncastCCParticipant
<OverOutElementsWrapper>(p); ImplCycleCollectionUnlink(
tmp->mDeepestEnterEventTarget); ImplCycleCollectionUnlink(
tmp->mDispatchingOverEventTarget); ImplCycleCollectionUnlink
(tmp->mDispatchingOutOrDeepestLeaveEventTarget); (void)tmp
; } nsresult OverOutElementsWrapper::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { OverOutElementsWrapper
* tmp = DowncastCCParticipant<OverOutElementsWrapper>(p
); cb.DescribeRefCountedNode(tmp->mRefCnt.get(), "OverOutElementsWrapper"
); ImplCycleCollectionTraverse(cb, tmp->mDeepestEnterEventTarget
, "mDeepestEnterEventTarget", 0); ImplCycleCollectionTraverse
(cb, tmp->mDispatchingOverEventTarget, "mDispatchingOverEventTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDispatchingOutOrDeepestLeaveEventTarget
, "mDispatchingOutOrDeepestLeaveEventTarget", 0); (void)tmp; return
NS_OK; }
291 mDispatchingOverEventTarget,OverOutElementsWrapper::cycleCollection OverOutElementsWrapper
::_cycleCollectorGlobal; void OverOutElementsWrapper::cycleCollection
::Unlink(void* p) { OverOutElementsWrapper* tmp = DowncastCCParticipant
<OverOutElementsWrapper>(p); ImplCycleCollectionUnlink(
tmp->mDeepestEnterEventTarget); ImplCycleCollectionUnlink(
tmp->mDispatchingOverEventTarget); ImplCycleCollectionUnlink
(tmp->mDispatchingOutOrDeepestLeaveEventTarget); (void)tmp
; } nsresult OverOutElementsWrapper::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { OverOutElementsWrapper
* tmp = DowncastCCParticipant<OverOutElementsWrapper>(p
); cb.DescribeRefCountedNode(tmp->mRefCnt.get(), "OverOutElementsWrapper"
); ImplCycleCollectionTraverse(cb, tmp->mDeepestEnterEventTarget
, "mDeepestEnterEventTarget", 0); ImplCycleCollectionTraverse
(cb, tmp->mDispatchingOverEventTarget, "mDispatchingOverEventTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDispatchingOutOrDeepestLeaveEventTarget
, "mDispatchingOutOrDeepestLeaveEventTarget", 0); (void)tmp; return
NS_OK; }
292 mDispatchingOutOrDeepestLeaveEventTarget)OverOutElementsWrapper::cycleCollection OverOutElementsWrapper
::_cycleCollectorGlobal; void OverOutElementsWrapper::cycleCollection
::Unlink(void* p) { OverOutElementsWrapper* tmp = DowncastCCParticipant
<OverOutElementsWrapper>(p); ImplCycleCollectionUnlink(
tmp->mDeepestEnterEventTarget); ImplCycleCollectionUnlink(
tmp->mDispatchingOverEventTarget); ImplCycleCollectionUnlink
(tmp->mDispatchingOutOrDeepestLeaveEventTarget); (void)tmp
; } nsresult OverOutElementsWrapper::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { OverOutElementsWrapper
* tmp = DowncastCCParticipant<OverOutElementsWrapper>(p
); cb.DescribeRefCountedNode(tmp->mRefCnt.get(), "OverOutElementsWrapper"
); ImplCycleCollectionTraverse(cb, tmp->mDeepestEnterEventTarget
, "mDeepestEnterEventTarget", 0); ImplCycleCollectionTraverse
(cb, tmp->mDispatchingOverEventTarget, "mDispatchingOverEventTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDispatchingOutOrDeepestLeaveEventTarget
, "mDispatchingOutOrDeepestLeaveEventTarget", 0); (void)tmp; return
NS_OK; }
293NS_IMPL_CYCLE_COLLECTING_ADDREF(OverOutElementsWrapper)MozExternalRefCountType OverOutElementsWrapper::AddRef(void) {
static_assert(!std::is_destructible_v<OverOutElementsWrapper
>, "Reference-counted class " "OverOutElementsWrapper" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 293); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
293; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); _mOwningThread.AssertOwnership("OverOutElementsWrapper"
" not thread-safe"); nsISupports* base = OverOutElementsWrapper
::cycleCollection::Upcast(this); nsrefcnt count = mRefCnt.incr
(base); NS_LogAddRef((this), (count), ("OverOutElementsWrapper"
), (uint32_t)(sizeof(*this))); return count; }
294NS_IMPL_CYCLE_COLLECTING_RELEASE(OverOutElementsWrapper)MozExternalRefCountType OverOutElementsWrapper::Release(void)
{ do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 294); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 294
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); _mOwningThread.AssertOwnership("OverOutElementsWrapper"
" not thread-safe"); nsISupports* base = OverOutElementsWrapper
::cycleCollection::Upcast(this); nsrefcnt count = mRefCnt.decr
(base); NS_LogRelease((this), (count), ("OverOutElementsWrapper"
)); return count; } void OverOutElementsWrapper::DeleteCycleCollectable
(void) { delete (this); }
295
296NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(OverOutElementsWrapper)nsresult OverOutElementsWrapper::QueryInterface(const nsIID&
aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 296); MOZ_PretendNoReturn(); } } while (0); nsISupports* foundInterface
; if (TopThreeWordsEquals( aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID), (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID)) && (LowWordEquals(aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID)) || LowWordEquals(aIID, (nsCycleCollectionISupports::COMTypeInfo
<nsCycleCollectionISupports, void>::kIID)))) { if (LowWordEquals
(aIID, (nsXPCOMCycleCollectionParticipant::COMTypeInfo<nsXPCOMCycleCollectionParticipant
, void>::kIID))) { *aInstancePtr = OverOutElementsWrapper::
cycleCollection::GetParticipant(); return NS_OK; } if (LowWordEquals
(aIID, (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID))) { *aInstancePtr = OverOutElementsWrapper::
cycleCollection::Upcast(this); return NS_OK; } foundInterface
= nullptr; } else
297 NS_INTERFACE_MAP_ENTRY(nsISupports)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupports>)) foundInterface = static_cast
<nsISupports*>(this); else
298NS_INTERFACE_MAP_ENDfoundInterface = 0; nsresult status; if (!foundInterface) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(!aIID.Equals((nsISupports::COMTypeInfo<nsISupports
, void>::kIID)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aIID.Equals((nsISupports::COMTypeInfo
<nsISupports, void>::kIID))))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 298); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
")"); do { *((volatile int*)__null) = 298; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); status = NS_NOINTERFACE
; } else { (foundInterface)->AddRef(); status = NS_OK; } *
aInstancePtr = foundInterface; return status; }
299
300already_AddRefed<nsIWidget> OverOutElementsWrapper::GetLastOverWidget() const {
301 nsCOMPtr<nsIWidget> widget = do_QueryReferent(mLastOverWidget);
302 return widget.forget();
303}
304
305void OverOutElementsWrapper::ContentRemoved(nsIContent& aContent) {
306 if (!mDeepestEnterEventTarget) {
307 return;
308 }
309
310 if (!nsContentUtils::ContentIsFlattenedTreeDescendantOf(
311 mDeepestEnterEventTarget, &aContent)) {
312 return;
313 }
314
315 LogModule* const logModule = mType == BoundaryEventType::Mouse
316 ? sMouseBoundaryLog
317 : sPointerBoundaryLog;
318
319 if (!StaticPrefs::
320 dom_events_mouse_pointer_boundary_keep_enter_targets_after_over_target_removed()) {
321 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"over\" event target (%p) is removed"
, mDeepestEnterEventTarget.get()); } } while (0)
322 ("The last \"over\" event target (%p) is removed",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"over\" event target (%p) is removed"
, mDeepestEnterEventTarget.get()); } } while (0)
323 mDeepestEnterEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"over\" event target (%p) is removed"
, mDeepestEnterEventTarget.get()); } } while (0)
;
324 StoreOverEventTargetAndDeepestEnterEventTarget(nullptr);
325 return;
326 }
327
328 if (mDispatchingOverEventTarget &&
329 (mDeepestEnterEventTarget == mDispatchingOverEventTarget ||
330 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
331 mDispatchingOverEventTarget, &aContent))) {
332 if (mDispatchingOverEventTarget ==
333 mDispatchingOutOrDeepestLeaveEventTarget) {
334 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
335 ("The dispatching \"%s\" event target (%p) is removed",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
336 LastOverEventTargetIsOutEventTarget() ? "out" : "leave",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
337 mDispatchingOutOrDeepestLeaveEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
;
338 mDispatchingOutOrDeepestLeaveEventTarget = nullptr;
339 }
340 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"over\" event target (%p) is removed"
, mDispatchingOverEventTarget.get()); } } while (0)
341 ("The dispatching \"over\" event target (%p) is removed",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"over\" event target (%p) is removed"
, mDispatchingOverEventTarget.get()); } } while (0)
342 mDispatchingOverEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"over\" event target (%p) is removed"
, mDispatchingOverEventTarget.get()); } } while (0)
;
343 mDispatchingOverEventTarget = nullptr;
344 }
345 if (mDispatchingOutOrDeepestLeaveEventTarget &&
346 (mDeepestEnterEventTarget == mDispatchingOutOrDeepestLeaveEventTarget ||
347 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
348 mDispatchingOutOrDeepestLeaveEventTarget, &aContent))) {
349 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
350 ("The dispatching \"%s\" event target (%p) is removed",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
351 LastOverEventTargetIsOutEventTarget() ? "out" : "leave",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
352 mDispatchingOutOrDeepestLeaveEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
;
353 mDispatchingOutOrDeepestLeaveEventTarget = nullptr;
354 }
355 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
356 ("The last \"%s\" event target (%p) is removed and now the last "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
357 "deepest enter target becomes %s(%p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
358 LastOverEventTargetIsOutEventTarget() ? "over" : "enter",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
359 mDeepestEnterEventTarget.get(),do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
360 aContent.GetFlattenedTreeParent()do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
361 ? ToString(*aContent.GetFlattenedTreeParent()).c_str()do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
362 : "nullptr",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
363 aContent.GetFlattenedTreeParent()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
;
364 UpdateDeepestEnterEventTarget(aContent.GetFlattenedTreeParent());
365}
366
367void OverOutElementsWrapper::TryToRestorePendingRemovedOverTarget(
368 const WidgetEvent* aEvent) {
369 if (!MaybeHasPendingRemovingOverEventTarget()) {
370 return;
371 }
372
373 LogModule* const logModule = mType == BoundaryEventType::Mouse
374 ? sMouseBoundaryLog
375 : sPointerBoundaryLog;
376
377 // If we receive a mouse event immediately, let's try to restore the last
378 // "over" event target as the following "out" event target. We assume that a
379 // synthesized mousemove or another mouse event is being dispatched at latest
380 // the next animation frame from the removal. However, synthesized mouse move
381 // which is enqueued by ContentRemoved() may not sent to this instance because
382 // the target is considered with the latest layout, so the document of this
383 // instance may be moved somewhere before the next animation frame.
384 // Therefore, we should not restore the last "over" target if we receive an
385 // unexpected event like a keyboard event, a wheel event, etc.
386 if (aEvent->AsMouseEvent()) {
387 // Restore the original "over" event target should be allowed only when it's
388 // reconnected under the last deepest "enter" event target because we need
389 // to dispatch "leave" events later at least on the ancestors which have
390 // never been removed from the tree.
391 // XXX If new ancestor is inserted between mDeepestEnterEventTarget and
392 // mPendingToRemoveLastOverEventTarget, we will dispatch "leave" event even
393 // though we have not dispatched "enter" event on the element. For fixing
394 // this, we need to store the full path of the last "out" event target when
395 // it's removed from the tree. I guess we can be relax for this issue
396 // because this hack is required for web apps which reconnect the target
397 // to the same position immediately.
398 // XXX Should be IsInclusiveFlatTreeDescendantOf()? However, it may
399 // be reconnected into a subtree which is different from where the
400 // last over element was.
401 nsCOMPtr<nsIContent> pendingRemovingOverEventTarget =
402 GetPendingRemovingOverEventTarget();
403 if (pendingRemovingOverEventTarget &&
404 pendingRemovingOverEventTarget->IsInclusiveDescendantOf(
405 mDeepestEnterEventTarget)) {
406 // StoreOverEventTargetAndDeepestEnterEventTarget() always resets
407 // mLastOverWidget. When we restore the pending removing "over" event
408 // target, we need to keep storing the original "over" widget too.
409 nsCOMPtr<nsIWeakReference> widget = std::move(mLastOverWidget);
410 StoreOverEventTargetAndDeepestEnterEventTarget(
411 pendingRemovingOverEventTarget);
412 mLastOverWidget = std::move(widget);
413 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
414 ("The \"over\" event target (%p) is restored",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
415 mDeepestEnterEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
;
416 return;
417 }
418 MOZ_LOG(logModule, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
419 ("Forgetting the last \"over\" event target (%p) because it is not "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
420 "reconnected under the deepest enter event target (%p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
421 mPendingRemovingOverEventTarget.get(),do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
422 mDeepestEnterEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
;
423 } else {
424 MOZ_LOG(logModule, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
425 ("Forgetting the last \"over\" event target (%p) because an "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
426 "unexpected event (%s) is being dispatched, that means that "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
427 "EventStateManager didn't receive a synthesized mousemove which "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
428 "should be dispatched at next animation frame from the removal",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
429 mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage)))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
;
430 }
431
432 // Now, we should not restore mPendingRemovingOverEventTarget to
433 // mDeepestEnterEventTarget anymore since mPendingRemovingOverEventTarget was
434 // moved outside the subtree of mDeepestEnterEventTarget.
435 mPendingRemovingOverEventTarget = nullptr;
436}
437
438void OverOutElementsWrapper::WillDispatchOverAndEnterEvent(
439 nsIContent* aOverEventTarget) {
440 StoreOverEventTargetAndDeepestEnterEventTarget(aOverEventTarget);
441 // Store the first "over" event target we fire and don't refire "over" event
442 // to that element while the first "over" event is still ongoing.
443 mDispatchingOverEventTarget = aOverEventTarget;
444}
445
446void OverOutElementsWrapper::DidDispatchOverAndEnterEvent(
447 nsIContent* aOriginalOverTargetInComposedDoc,
448 nsIWidget* aOverEventTargetWidget) {
449 mDispatchingOverEventTarget = nullptr;
450 mLastOverWidget = do_GetWeakReference(aOverEventTargetWidget);
451
452 // Pointer Events define that once the `pointerover` event target is removed
453 // from the tree, `pointerout` should not be fired on that and the closest
454 // connected ancestor at the target removal should be kept as the deepest
455 // `pointerleave` target. Therefore, we don't need the special handling for
456 // `pointerout` event target if the last `pointerover` target is temporarily
457 // removed from the tree.
458 if (mType == OverOutElementsWrapper::BoundaryEventType::Pointer) {
459 return;
460 }
461
462 // Assume that the caller checks whether aOriginalOverTarget is in the
463 // original document. If we don't enable the strict mouse/pointer event
464 // boundary event dispatching by the pref (see below),
465 // mDeepestEnterEventTarget is set to nullptr when the last "over" target is
466 // removed. Therefore, we cannot check whether aOriginalOverTarget is in the
467 // original document here.
468 if (!aOriginalOverTargetInComposedDoc) {
469 return;
470 }
471 MOZ_ASSERT_IF(mDeepestEnterEventTarget,do { if (mDeepestEnterEventTarget) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mDeepestEnterEventTarget
->GetComposedDoc() == aOriginalOverTargetInComposedDoc->
GetComposedDoc())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget->
GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
")"); do { *((volatile int*)__null) = 473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
472 mDeepestEnterEventTarget->GetComposedDoc() ==do { if (mDeepestEnterEventTarget) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mDeepestEnterEventTarget
->GetComposedDoc() == aOriginalOverTargetInComposedDoc->
GetComposedDoc())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget->
GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
")"); do { *((volatile int*)__null) = 473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
473 aOriginalOverTargetInComposedDoc->GetComposedDoc())do { if (mDeepestEnterEventTarget) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mDeepestEnterEventTarget
->GetComposedDoc() == aOriginalOverTargetInComposedDoc->
GetComposedDoc())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget->
GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
")"); do { *((volatile int*)__null) = 473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
474 // If the "mouseover" event target is removed temporarily while we're
475 // dispatching "mouseover" and "mouseenter" events and the target gets back
476 // under the deepest enter event target, we should restore the "mouseover"
477 // target.
478 if ((!StaticPrefs::
479 dom_events_mouse_pointer_boundary_keep_enter_targets_after_over_target_removed() &&
480 !mDeepestEnterEventTarget) ||
481 (!LastOverEventTargetIsOutEventTarget() && mDeepestEnterEventTarget &&
482 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
483 aOriginalOverTargetInComposedDoc, mDeepestEnterEventTarget))) {
484 StoreOverEventTargetAndDeepestEnterEventTarget(
485 aOriginalOverTargetInComposedDoc);
486 LogModule* const logModule = mType == BoundaryEventType::Mouse
487 ? sMouseBoundaryLog
488 : sPointerBoundaryLog;
489 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
490 ("The \"over\" event target (%p) is restored",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
491 mDeepestEnterEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
;
492 }
493}
494
495void OverOutElementsWrapper::StoreOverEventTargetAndDeepestEnterEventTarget(
496 nsIContent* aOverEventTargetAndDeepestEnterEventTarget) {
497 mDeepestEnterEventTarget = aOverEventTargetAndDeepestEnterEventTarget;
498 mPendingRemovingOverEventTarget = nullptr;
499 mDeepestEnterEventTargetIsOverEventTarget = !!mDeepestEnterEventTarget;
500 mLastOverWidget = nullptr; // Set it after dispatching the "over" event.
501}
502
503void OverOutElementsWrapper::UpdateDeepestEnterEventTarget(
504 nsIContent* aDeepestEnterEventTarget) {
505 if (MOZ_UNLIKELY(mDeepestEnterEventTarget == aDeepestEnterEventTarget)(__builtin_expect(!!(mDeepestEnterEventTarget == aDeepestEnterEventTarget
), 0))
) {
506 return;
507 }
508
509 if (!aDeepestEnterEventTarget) {
510 // If the root element is removed, we don't need to dispatch "leave"
511 // events on any elements. Therefore, we can forget everything.
512 StoreOverEventTargetAndDeepestEnterEventTarget(nullptr);
513 return;
514 }
515
516 if (LastOverEventTargetIsOutEventTarget()) {
517 MOZ_ASSERT(mDeepestEnterEventTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDeepestEnterEventTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("mDeepestEnterEventTarget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 517); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget"
")"); do { *((volatile int*)__null) = 517; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
518 if (mType == BoundaryEventType::Pointer) {
519 // The spec of Pointer Events defines that once the `pointerover` event
520 // target is removed from the tree, `pointerout` should not be fired on
521 // that and the closest connected ancestor at the target removal should be
522 // kept as the deepest `pointerleave` target. All browsers considers the
523 // last `pointerover` event target is removed immediately when it occurs.
524 // Therefore, we don't need the special handling which we do for the
525 // `mouseout` event target below for considering whether we'll dispatch
526 // `pointerout` on the last `pointerover` target.
527 mPendingRemovingOverEventTarget = nullptr;
528 } else {
529 // Now, the `mouseout` event target is removed from the DOM at least
530 // temporarily. Let's keep storing it for restoring it if it's
531 // reconnected into mDeepestEnterEventTarget in a tick because the other
532 // browsers do not treat temporary removal of the last `mouseover` target
533 // keeps storing it as the next `mouseout` event target.
534 MOZ_ASSERT(!mPendingRemovingOverEventTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mPendingRemovingOverEventTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mPendingRemovingOverEventTarget
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!mPendingRemovingOverEventTarget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 534); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mPendingRemovingOverEventTarget"
")"); do { *((volatile int*)__null) = 534; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
535 MOZ_ASSERT(mDeepestEnterEventTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDeepestEnterEventTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("mDeepestEnterEventTarget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 535); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget"
")"); do { *((volatile int*)__null) = 535; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
536 mPendingRemovingOverEventTarget =
537 do_GetWeakReference(mDeepestEnterEventTarget);
538 }
539 } else {
540 MOZ_ASSERT(!mDeepestEnterEventTargetIsOverEventTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDeepestEnterEventTargetIsOverEventTarget)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!mDeepestEnterEventTargetIsOverEventTarget))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!mDeepestEnterEventTargetIsOverEventTarget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 540); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDeepestEnterEventTargetIsOverEventTarget"
")"); do { *((volatile int*)__null) = 540; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
541 // If mDeepestEnterEventTarget is not the last "over" event target, we've
542 // already done the complicated state managing above. Therefore, we only
543 // need to update mDeepestEnterEventTarget in this case.
544 }
545 mDeepestEnterEventTarget = aDeepestEnterEventTarget;
546 mDeepestEnterEventTargetIsOverEventTarget = false;
547 // Do not update mLastOverWidget here because it's required to ignore some
548 // following pointer events which are fired on widget under different top
549 // level widget.
550}
551
552/******************************************************************/
553/* mozilla::EventStateManager */
554/******************************************************************/
555
556static uint32_t sESMInstanceCount = 0;
557
558bool EventStateManager::sNormalLMouseEventInProcess = false;
559int16_t EventStateManager::sCurrentMouseBtn = MouseButton::eNotPressed;
560EventStateManager* EventStateManager::sActiveESM = nullptr;
561EventStateManager* EventStateManager::sCursorSettingManager = nullptr;
562AutoWeakFrame EventStateManager::sLastDragOverFrame = nullptr;
563LayoutDeviceIntPoint EventStateManager::sPreLockScreenPoint =
564 LayoutDeviceIntPoint(0, 0);
565LayoutDeviceIntPoint EventStateManager::sLastRefPoint = kInvalidRefPoint;
566CSSIntPoint EventStateManager::sLastScreenPoint = CSSIntPoint(0, 0);
567LayoutDeviceIntPoint EventStateManager::sSynthCenteringPoint = kInvalidRefPoint;
568CSSIntPoint EventStateManager::sLastClientPoint = CSSIntPoint(0, 0);
569nsCOMPtr<nsIContent> EventStateManager::sDragOverContent = nullptr;
570
571EventStateManager::WheelPrefs* EventStateManager::WheelPrefs::sInstance =
572 nullptr;
573EventStateManager::DeltaAccumulator*
574 EventStateManager::DeltaAccumulator::sInstance = nullptr;
575
576constexpr const StyleCursorKind kInvalidCursorKind =
577 static_cast<StyleCursorKind>(255);
578
579EventStateManager::EventStateManager()
580 : mLockCursor(kInvalidCursorKind),
581 mCurrentTarget(nullptr),
582 // init d&d gesture state machine variables
583 mGestureDownPoint(0, 0),
584 mGestureModifiers(0),
585 mGestureDownButtons(0),
586 mGestureDownButton(0),
587 mPresContext(nullptr),
588 mShouldAlwaysUseLineDeltas(false),
589 mShouldAlwaysUseLineDeltasInitialized(false),
590 mGestureDownInTextControl(false),
591 mInTouchDrag(false),
592 m_haveShutdown(false) {
593 if (sESMInstanceCount == 0) {
594 gUserInteractionTimerCallback = new UITimerCallback();
595 if (gUserInteractionTimerCallback) NS_ADDREF(gUserInteractionTimerCallback)(gUserInteractionTimerCallback)->AddRef();
596 UpdateUserActivityTimer();
597 }
598 ++sESMInstanceCount;
599}
600
601nsresult EventStateManager::UpdateUserActivityTimer() {
602 if (!gUserInteractionTimerCallback) return NS_OK;
603
604 if (!gUserInteractionTimer) {
605 gUserInteractionTimer = NS_NewTimer().take();
606 }
607
608 if (gUserInteractionTimer) {
609 gUserInteractionTimer->InitWithCallback(
610 gUserInteractionTimerCallback,
611 StaticPrefs::dom_events_user_interaction_interval(),
612 nsITimer::TYPE_ONE_SHOT);
613 }
614 return NS_OK;
615}
616
617nsresult EventStateManager::Init() {
618 nsCOMPtr<nsIObserverService> observerService =
619 mozilla::services::GetObserverService();
620 if (!observerService) return NS_ERROR_FAILURE;
621
622 observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown", true);
623
624 return NS_OK;
625}
626
627bool EventStateManager::ShouldAlwaysUseLineDeltas() {
628 if (MOZ_UNLIKELY(!mShouldAlwaysUseLineDeltasInitialized)(__builtin_expect(!!(!mShouldAlwaysUseLineDeltasInitialized),
0))
) {
629 mShouldAlwaysUseLineDeltasInitialized = true;
630 mShouldAlwaysUseLineDeltas =
631 !StaticPrefs::dom_event_wheel_deltaMode_lines_disabled();
632 if (!mShouldAlwaysUseLineDeltas && mDocument) {
633 if (nsIPrincipal* principal =
634 mDocument->GetPrincipalForPrefBasedHacks()) {
635 mShouldAlwaysUseLineDeltas = principal->IsURIInPrefList(
636 "dom.event.wheel-deltaMode-lines.always-enabled");
637 }
638 }
639 }
640 return mShouldAlwaysUseLineDeltas;
641}
642
643EventStateManager::~EventStateManager() {
644 ReleaseCurrentIMEContentObserver();
645
646 if (sActiveESM == this) {
647 sActiveESM = nullptr;
648 }
649
650 if (StaticPrefs::ui_click_hold_context_menus()) {
651 KillClickHoldTimer();
652 }
653
654 if (sCursorSettingManager == this) {
655 sCursorSettingManager = nullptr;
656 }
657
658 --sESMInstanceCount;
659 if (sESMInstanceCount == 0) {
660 WheelTransaction::Shutdown();
661 if (gUserInteractionTimerCallback) {
662 gUserInteractionTimerCallback->Notify(nullptr);
663 NS_RELEASE(gUserInteractionTimerCallback)do { (gUserInteractionTimerCallback)->Release(); (gUserInteractionTimerCallback
) = 0; } while (0)
;
664 }
665 if (gUserInteractionTimer) {
666 gUserInteractionTimer->Cancel();
667 NS_RELEASE(gUserInteractionTimer)do { (gUserInteractionTimer)->Release(); (gUserInteractionTimer
) = 0; } while (0)
;
668 }
669 WheelPrefs::Shutdown();
670 DeltaAccumulator::Shutdown();
671 }
672
673 if (sDragOverContent && sDragOverContent->OwnerDoc() == mDocument) {
674 sDragOverContent = nullptr;
675 }
676
677 if (!m_haveShutdown) {
678 Shutdown();
679
680 // Don't remove from Observer service in Shutdown because Shutdown also
681 // gets called from xpcom shutdown observer. And we don't want to remove
682 // from the service in that case.
683
684 nsCOMPtr<nsIObserverService> observerService =
685 mozilla::services::GetObserverService();
686 if (observerService) {
687 observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown");
688 }
689 }
690}
691
692nsresult EventStateManager::Shutdown() {
693 m_haveShutdown = true;
694 return NS_OK;
695}
696
697NS_IMETHODIMPnsresult
698EventStateManager::Observe(nsISupports* aSubject, const char* aTopic,
699 const char16_t* someData) {
700 if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown")) {
701 Shutdown();
702 }
703
704 return NS_OK;
705}
706
707NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(EventStateManager)nsresult EventStateManager::QueryInterface(const nsIID& aIID
, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 707); MOZ_PretendNoReturn(); } } while (0); nsISupports* foundInterface
; if (TopThreeWordsEquals( aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID), (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID)) && (LowWordEquals(aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID)) || LowWordEquals(aIID, (nsCycleCollectionISupports::COMTypeInfo
<nsCycleCollectionISupports, void>::kIID)))) { if (LowWordEquals
(aIID, (nsXPCOMCycleCollectionParticipant::COMTypeInfo<nsXPCOMCycleCollectionParticipant
, void>::kIID))) { *aInstancePtr = EventStateManager::cycleCollection
::GetParticipant(); return NS_OK; } if (LowWordEquals(aIID, (
nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID))) { *aInstancePtr = EventStateManager::cycleCollection
::Upcast(this); return NS_OK; } foundInterface = nullptr; } else
708 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupports>)) foundInterface = static_cast
<nsISupports*>(static_cast<nsIObserver*>(this)); else
709 NS_INTERFACE_MAP_ENTRY(nsIObserver)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIObserver>)) foundInterface = static_cast
<nsIObserver*>(this); else
710 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupportsWeakReference>)) foundInterface
= static_cast<nsISupportsWeakReference*>(this); else
711NS_INTERFACE_MAP_ENDfoundInterface = 0; nsresult status; if (!foundInterface) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(!aIID.Equals((nsISupports::COMTypeInfo<nsISupports
, void>::kIID)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aIID.Equals((nsISupports::COMTypeInfo
<nsISupports, void>::kIID))))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 711); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
")"); do { *((volatile int*)__null) = 711; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); status = NS_NOINTERFACE
; } else { (foundInterface)->AddRef(); status = NS_OK; } *
aInstancePtr = foundInterface; return status; }
712
713NS_IMPL_CYCLE_COLLECTING_ADDREF(EventStateManager)MozExternalRefCountType EventStateManager::AddRef(void) { static_assert
(!std::is_destructible_v<EventStateManager>, "Reference-counted class "
"EventStateManager" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 713); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
713; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); _mOwningThread.AssertOwnership("EventStateManager"
" not thread-safe"); nsISupports* base = EventStateManager::
cycleCollection::Upcast(this); nsrefcnt count = mRefCnt.incr(
base); NS_LogAddRef((this), (count), ("EventStateManager"), (
uint32_t)(sizeof(*this))); return count; }
714NS_IMPL_CYCLE_COLLECTING_RELEASE(EventStateManager)MozExternalRefCountType EventStateManager::Release(void) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 714); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 714
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); _mOwningThread.AssertOwnership("EventStateManager" " not thread-safe"
); nsISupports* base = EventStateManager::cycleCollection::Upcast
(this); nsrefcnt count = mRefCnt.decr(base); NS_LogRelease((this
), (count), ("EventStateManager")); return count; } void EventStateManager
::DeleteCycleCollectable(void) { delete (this); }
715
716NS_IMPL_CYCLE_COLLECTION_WEAK(EventStateManager, mCurrentTargetContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
717 mGestureDownContent, mGestureDownFrameOwner,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
718 mLastLeftMouseDownInfo.mLastMouseDownContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
719 mLastMiddleMouseDownInfo.mLastMouseDownContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
720 mLastRightMouseDownInfo.mLastMouseDownContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
721 mActiveContent, mHoverContent, mURLTargetContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
722 mPopoverPointerDownTarget, mMouseEnterLeaveHelper,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
723 mPointersEnterLeaveHelper, mDocument,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
724 mIMEContentObserver, mAccessKeys)EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
725
726void EventStateManager::ReleaseCurrentIMEContentObserver() {
727 if (mIMEContentObserver) {
728 mIMEContentObserver->DisconnectFromEventStateManager();
729 }
730 mIMEContentObserver = nullptr;
731}
732
733void EventStateManager::OnStartToObserveContent(
734 IMEContentObserver* aIMEContentObserver) {
735 if (mIMEContentObserver == aIMEContentObserver) {
736 return;
737 }
738 ReleaseCurrentIMEContentObserver();
739 mIMEContentObserver = aIMEContentObserver;
740}
741
742void EventStateManager::OnStopObservingContent(
743 IMEContentObserver* aIMEContentObserver) {
744 aIMEContentObserver->DisconnectFromEventStateManager();
745 NS_ENSURE_TRUE_VOID(mIMEContentObserver == aIMEContentObserver)do { if ((__builtin_expect(!!(!(mIMEContentObserver == aIMEContentObserver
)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mIMEContentObserver == aIMEContentObserver"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 745); return; } } while (false)
;
746 mIMEContentObserver = nullptr;
747}
748
749void EventStateManager::TryToFlushPendingNotificationsToIME() {
750 if (mIMEContentObserver) {
751 mIMEContentObserver->TryToFlushPendingNotifications(true);
752 }
753}
754
755static bool IsMessageMouseUserActivity(EventMessage aMessage) {
756 return aMessage == eMouseMove || aMessage == eMouseUp ||
757 aMessage == eMouseDown || aMessage == ePointerAuxClick ||
758 aMessage == eMouseDoubleClick || aMessage == ePointerClick ||
759 aMessage == eMouseActivate || aMessage == eMouseLongTap;
760}
761
762static bool IsMessageGamepadUserActivity(EventMessage aMessage) {
763 return aMessage == eGamepadButtonDown || aMessage == eGamepadButtonUp ||
764 aMessage == eGamepadAxisMove;
765}
766
767// static
768bool EventStateManager::IsKeyboardEventUserActivity(WidgetEvent* aEvent) {
769 // We ignore things that shouldn't cause popups, but also things that look
770 // like shortcut presses. In some obscure cases these may actually be
771 // website input, but any meaningful website will have other input anyway,
772 // and we can't very well tell whether shortcut input was supposed to be
773 // directed at chrome or the document.
774
775 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
776 // Access keys should be treated as page interaction.
777 if (keyEvent->ModifiersMatchWithAccessKey(AccessKeyType::eContent)) {
778 return true;
779 }
780 if (!keyEvent->CanTreatAsUserInput() || keyEvent->IsControl() ||
781 keyEvent->IsMeta() || keyEvent->IsAlt()) {
782 return false;
783 }
784 // Deal with function keys:
785 switch (keyEvent->mKeyNameIndex) {
786 case KEY_NAME_INDEX_F1:
787 case KEY_NAME_INDEX_F2:
788 case KEY_NAME_INDEX_F3:
789 case KEY_NAME_INDEX_F4:
790 case KEY_NAME_INDEX_F5:
791 case KEY_NAME_INDEX_F6:
792 case KEY_NAME_INDEX_F7:
793 case KEY_NAME_INDEX_F8:
794 case KEY_NAME_INDEX_F9:
795 case KEY_NAME_INDEX_F10:
796 case KEY_NAME_INDEX_F11:
797 case KEY_NAME_INDEX_F12:
798 case KEY_NAME_INDEX_F13:
799 case KEY_NAME_INDEX_F14:
800 case KEY_NAME_INDEX_F15:
801 case KEY_NAME_INDEX_F16:
802 case KEY_NAME_INDEX_F17:
803 case KEY_NAME_INDEX_F18:
804 case KEY_NAME_INDEX_F19:
805 case KEY_NAME_INDEX_F20:
806 case KEY_NAME_INDEX_F21:
807 case KEY_NAME_INDEX_F22:
808 case KEY_NAME_INDEX_F23:
809 case KEY_NAME_INDEX_F24:
810 return false;
811 default:
812 return true;
813 }
814}
815
816static void OnTypingInteractionEnded() {
817 // We don't consider a single keystroke to be typing.
818 if (gTypingInteractionKeyPresses > 1) {
819 gTypingInteraction.mInteractionCount += gTypingInteractionKeyPresses;
820 gTypingInteraction.mInteractionTimeInMilliseconds += static_cast<uint32_t>(
821 std::ceil((gTypingEndTime - gTypingStartTime).ToMilliseconds()));
822 }
823
824 gTypingInteractionKeyPresses = 0;
825 gTypingStartTime = TimeStamp();
826 gTypingEndTime = TimeStamp();
827}
828
829static void HandleKeyUpInteraction(WidgetKeyboardEvent* aKeyEvent) {
830 if (EventStateManager::IsKeyboardEventUserActivity(aKeyEvent)) {
831 TimeStamp now = TimeStamp::Now();
832 if (gTypingEndTime.IsNull()) {
833 gTypingEndTime = now;
834 }
835 TimeDuration delay = now - gTypingEndTime;
836 // Has it been too long since the last keystroke to be considered typing?
837 if (gTypingInteractionKeyPresses > 0 &&
838 delay >
839 TimeDuration::FromMilliseconds(
840 StaticPrefs::browser_places_interactions_typing_timeout_ms())) {
841 OnTypingInteractionEnded();
842 }
843 gTypingInteractionKeyPresses++;
844 if (gTypingStartTime.IsNull()) {
845 gTypingStartTime = now;
846 }
847 gTypingEndTime = now;
848 }
849}
850
851nsresult EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
852 WidgetEvent* aEvent,
853 nsIFrame* aTargetFrame,
854 nsIContent* aTargetContent,
855 nsEventStatus* aStatus,
856 nsIContent* aOverrideClickTarget) {
857 AUTO_PROFILER_LABEL("EventStateManager::PreHandleEvent", DOM)mozilla::AutoProfilerLabel raiiObject857( "EventStateManager::PreHandleEvent"
, nullptr, JS::ProfilingCategoryPair::DOM)
;
858 NS_ENSURE_ARG_POINTER(aStatus)do { if ((__builtin_expect(!!(!(aStatus)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStatus" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 858); return NS_ERROR_INVALID_POINTER; } } while (false)
;
859 NS_ENSURE_ARG(aPresContext)do { if ((__builtin_expect(!!(!(aPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 859); return NS_ERROR_INVALID_ARG; } } while (false)
;
860 if (!aEvent) {
861 NS_ERROR("aEvent is null. This should never happen.")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "aEvent is null. This should never happen."
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 861); MOZ_PretendNoReturn(); } while (0)
;
862 return NS_ERROR_NULL_POINTER;
863 }
864
865 NS_WARNING_ASSERTION(do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
866 !aTargetFrame || !aTargetFrame->GetContent() ||do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
867 aTargetFrame->GetContent() == aTargetContent ||do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
868 aTargetFrame->GetContent()->GetFlattenedTreeParent() ==do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
869 aTargetContent ||do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
870 aTargetFrame->IsGeneratedContentFrame(),do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
871 "aTargetFrame should be related with aTargetContent")do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
;
872#if DEBUG1
873 if (aTargetFrame && aTargetFrame->IsGeneratedContentFrame()) {
874 nsCOMPtr<nsIContent> targetContent;
875 aTargetFrame->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
876 MOZ_ASSERT(aTargetContent == targetContent,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTargetContent == targetContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTargetContent == targetContent
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aTargetContent == targetContent" " (" "Unexpected target for generated content frame!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTargetContent == targetContent"
") (" "Unexpected target for generated content frame!" ")");
do { *((volatile int*)__null) = 877; __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
877 "Unexpected target for generated content frame!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTargetContent == targetContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTargetContent == targetContent
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aTargetContent == targetContent" " (" "Unexpected target for generated content frame!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTargetContent == targetContent"
") (" "Unexpected target for generated content frame!" ")");
do { *((volatile int*)__null) = 877; __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
878 }
879#endif
880
881 mCurrentTarget = aTargetFrame;
882 mCurrentTargetContent = nullptr;
883
884 // Do not take account eMouseEnterIntoWidget/ExitFromWidget so that loading
885 // a page when user is not active doesn't change the state to active.
886 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
887 if (aEvent->IsTrusted() &&
888 ((mouseEvent && mouseEvent->IsReal() &&
889 IsMessageMouseUserActivity(mouseEvent->mMessage)) ||
890 aEvent->mClass == eWheelEventClass ||
891 aEvent->mClass == ePointerEventClass ||
892 aEvent->mClass == eTouchEventClass ||
893 aEvent->mClass == eKeyboardEventClass ||
894 (aEvent->mClass == eDragEventClass && aEvent->mMessage == eDrop) ||
895 IsMessageGamepadUserActivity(aEvent->mMessage))) {
896 if (gMouseOrKeyboardEventCounter == 0) {
897 nsCOMPtr<nsIObserverService> obs =
898 mozilla::services::GetObserverService();
899 if (obs) {
900 obs->NotifyObservers(nullptr, "user-interaction-active", nullptr);
901 UpdateUserActivityTimer();
902 }
903 }
904 ++gMouseOrKeyboardEventCounter;
905
906 nsCOMPtr<nsINode> node = aTargetContent;
907 if (node &&
908 ((aEvent->mMessage == eKeyUp && IsKeyboardEventUserActivity(aEvent)) ||
909 aEvent->mMessage == eMouseUp || aEvent->mMessage == eWheel ||
910 aEvent->mMessage == eTouchEnd || aEvent->mMessage == ePointerUp ||
911 aEvent->mMessage == eDrop)) {
912 Document* doc = node->OwnerDoc();
913 while (doc) {
914 doc->SetUserHasInteracted();
915 doc = nsContentUtils::IsChildOfSameType(doc)
916 ? doc->GetInProcessParentDocument()
917 : nullptr;
918 }
919 }
920 }
921
922 WheelTransaction::OnEvent(aEvent);
923
924 // Focus events don't necessarily need a frame.
925 if (!mCurrentTarget && !aTargetContent) {
926 NS_ERROR("mCurrentTarget and aTargetContent are null")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "mCurrentTarget and aTargetContent are null"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 926); MOZ_PretendNoReturn(); } while (0)
;
927 return NS_ERROR_NULL_POINTER;
928 }
929#ifdef DEBUG1
930 if (aEvent->HasDragEventMessage() && PointerLockManager::IsLocked()) {
931 NS_ASSERTION(PointerLockManager::IsLocked(),do { if (!(PointerLockManager::IsLocked())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Pointer is locked. Drag events should be suppressed when "
"the pointer is locked.", "PointerLockManager::IsLocked()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 933); MOZ_PretendNoReturn(); } } while (0)
932 "Pointer is locked. Drag events should be suppressed when "do { if (!(PointerLockManager::IsLocked())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Pointer is locked. Drag events should be suppressed when "
"the pointer is locked.", "PointerLockManager::IsLocked()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 933); MOZ_PretendNoReturn(); } } while (0)
933 "the pointer is locked.")do { if (!(PointerLockManager::IsLocked())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Pointer is locked. Drag events should be suppressed when "
"the pointer is locked.", "PointerLockManager::IsLocked()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 933); MOZ_PretendNoReturn(); } } while (0)
;
934 }
935#endif
936 // Store last known screenPoint and clientPoint so pointer lock
937 // can use these values as constants.
938 if (aEvent->IsTrusted() &&
939 ((mouseEvent && mouseEvent->IsReal()) ||
940 aEvent->mClass == eWheelEventClass) &&
941 !PointerLockManager::IsLocked()) {
942 // XXX Probably doesn't matter much, but storing these in CSS pixels instead
943 // of device pixels means behavior can be a bit odd if you zoom while
944 // pointer-locked.
945 sLastScreenPoint =
946 Event::GetScreenCoords(aPresContext, aEvent, aEvent->mRefPoint)
947 .extract();
948 sLastClientPoint = Event::GetClientCoords(
949 aPresContext, aEvent, aEvent->mRefPoint, CSSIntPoint(0, 0));
950 }
951
952 *aStatus = nsEventStatus_eIgnore;
953
954 if (aEvent->mClass == eQueryContentEventClass) {
955 HandleQueryContentEvent(aEvent->AsQueryContentEvent());
956 return NS_OK;
957 }
958
959 WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
960 if (touchEvent && mInTouchDrag) {
961 if (touchEvent->mMessage == eTouchMove) {
962 GenerateDragGesture(aPresContext, touchEvent);
963 } else {
964 mInTouchDrag = false;
965 StopTrackingDragGesture(true);
966 }
967 }
968
969 if (mMouseEnterLeaveHelper && aEvent->IsTrusted()) {
970 // When the last `mouseover` event target is removed from the document,
971 // we makes mMouseEnterLeaveHelper update the last deepest `mouseenter`
972 // event target to the removed node parent and mark it as not the following
973 // `mouseout` event target. However, the other browsers may dispatch
974 // `mouseout` on it if it's restored "immediately". Therefore, we use
975 // the next animation frame as the deadline. ContentRemoved() enqueues a
976 // synthesized `mousemove` to dispatch mouse boundary events under the
977 // mouse cursor soon and the synthesized event (or eMouseExitFromWidget if
978 // our window is moved) will reach here at latest the next animation frame.
979 // Therefore, we can use the event as the deadline. If the removed last
980 // `mouseover` target is reconnected before a synthesized mouse event or
981 // a real mouse event, let's restore it as the following `mouseout` event
982 // target. Otherwise, e.g., a keyboard event, let's forget it.
983 mMouseEnterLeaveHelper->TryToRestorePendingRemovedOverTarget(aEvent);
984 }
985
986 static constexpr auto const allowSynthesisForTests = []() -> bool {
987 nsCOMPtr<nsIDragService> dragService =
988 do_GetService("@mozilla.org/widget/dragservice;1");
989 return dragService &&
990 !dragService->GetNeverAllowSessionIsSynthesizedForTests();
991 };
992
993 switch (aEvent->mMessage) {
994 case eContextMenu:
995 if (PointerLockManager::IsLocked()) {
996 return NS_ERROR_DOM_INVALID_STATE_ERR;
997 }
998 break;
999 case eMouseTouchDrag:
1000 mInTouchDrag = true;
1001 BeginTrackingDragGesture(aPresContext, mouseEvent, aTargetFrame);
1002 break;
1003 case eMouseDown: {
1004 switch (mouseEvent->mButton) {
1005 case MouseButton::ePrimary:
1006 BeginTrackingDragGesture(aPresContext, mouseEvent, aTargetFrame);
1007 mLastLeftMouseDownInfo.mClickCount = mouseEvent->mClickCount;
1008 SetClickCount(mouseEvent, aStatus);
1009 sNormalLMouseEventInProcess = true;
1010 break;
1011 case MouseButton::eMiddle:
1012 mLastMiddleMouseDownInfo.mClickCount = mouseEvent->mClickCount;
1013 SetClickCount(mouseEvent, aStatus);
1014 break;
1015 case MouseButton::eSecondary:
1016 mLastRightMouseDownInfo.mClickCount = mouseEvent->mClickCount;
1017 SetClickCount(mouseEvent, aStatus);
1018 break;
1019 }
1020 NotifyTargetUserActivation(aEvent, aTargetContent);
1021 break;
1022 }
1023 case eMouseUp: {
1024 switch (mouseEvent->mButton) {
1025 case MouseButton::ePrimary:
1026 if (StaticPrefs::ui_click_hold_context_menus()) {
1027 KillClickHoldTimer();
1028 }
1029 mInTouchDrag = false;
1030 StopTrackingDragGesture(true);
1031 sNormalLMouseEventInProcess = false;
1032 // then fall through...
1033 [[fallthrough]];
1034 case MouseButton::eSecondary:
1035 case MouseButton::eMiddle:
1036 RefPtr<EventStateManager> esm =
1037 ESMFromContentOrThis(aOverrideClickTarget);
1038 esm->SetClickCount(mouseEvent, aStatus, aOverrideClickTarget);
1039 break;
1040 }
1041 break;
1042 }
1043 case eMouseEnterIntoWidget:
1044 PointerEventHandler::UpdateActivePointerState(mouseEvent, aTargetContent);
1045 // In some cases on e10s eMouseEnterIntoWidget
1046 // event was sent twice into child process of content.
1047 // (From specific widget code (sending is not permanent) and
1048 // from ESM::DispatchMouseOrPointerBoundaryEvent (sending is permanent)).
1049 // IsCrossProcessForwardingStopped() helps to suppress sending accidental
1050 // event from widget code.
1051 aEvent->StopCrossProcessForwarding();
1052 break;
1053 case eMouseExitFromWidget:
1054 // If this is a remote frame, we receive eMouseExitFromWidget from the
1055 // parent the mouse exits our content. Since the parent may update the
1056 // cursor while the mouse is outside our frame, and since PuppetWidget
1057 // caches the current cursor internally, re-entering our content (say from
1058 // over a window edge) wont update the cursor if the cached value and the
1059 // current cursor match. So when the mouse exits a remote frame, clear the
1060 // cached widget cursor so a proper update will occur when the mouse
1061 // re-enters.
1062 if (XRE_IsContentProcess()) {
1063 ClearCachedWidgetCursor(mCurrentTarget);
1064 }
1065
1066 // IsCrossProcessForwardingStopped() helps to suppress double event
1067 // sending into process of content. For more information see comment
1068 // above, at eMouseEnterIntoWidget case.
1069 aEvent->StopCrossProcessForwarding();
1070
1071 // If the event is not a top-level window or puppet widget exit, then it's
1072 // not really an exit --- we may have traversed widget boundaries but
1073 // we're still in our toplevel window or puppet widget.
1074 if (mouseEvent->mExitFrom.value() !=
1075 WidgetMouseEvent::ePlatformTopLevel &&
1076 mouseEvent->mExitFrom.value() != WidgetMouseEvent::ePuppet) {
1077 // Treat it as a synthetic move so we don't generate spurious
1078 // "exit" or "move" events. Any necessary "out" or "over" events
1079 // will be generated by GenerateMouseEnterExit
1080 mouseEvent->mMessage = eMouseMove;
1081 mouseEvent->mReason = WidgetMouseEvent::eSynthesized;
1082 // then fall through...
1083 } else {
1084 MOZ_ASSERT_IF(XRE_IsParentProcess(),do { if (XRE_IsParentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePlatformTopLevel)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1086); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
")"); do { *((volatile int*)__null) = 1086; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1085 mouseEvent->mExitFrom.value() ==do { if (XRE_IsParentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePlatformTopLevel)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1086); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
")"); do { *((volatile int*)__null) = 1086; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1086 WidgetMouseEvent::ePlatformTopLevel)do { if (XRE_IsParentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePlatformTopLevel)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1086); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
")"); do { *((volatile int*)__null) = 1086; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1087 MOZ_ASSERT_IF(XRE_IsContentProcess(), mouseEvent->mExitFrom.value() ==do { if (XRE_IsContentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePuppet)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mouseEvent->mExitFrom.value
() == WidgetMouseEvent::ePuppet))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1088); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
")"); do { *((volatile int*)__null) = 1088; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1088 WidgetMouseEvent::ePuppet)do { if (XRE_IsContentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePuppet)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mouseEvent->mExitFrom.value
() == WidgetMouseEvent::ePuppet))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1088); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
")"); do { *((volatile int*)__null) = 1088; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1089 // We should synthetize corresponding pointer events
1090 GeneratePointerEnterExit(ePointerLeave, mouseEvent);
1091 GenerateMouseEnterExit(mouseEvent);
1092 // This is really an exit and should stop here
1093 aEvent->mMessage = eVoidEvent;
1094 break;
1095 }
1096 [[fallthrough]];
1097 case eMouseMove:
1098 case ePointerDown:
1099 if (aEvent->mMessage == ePointerDown) {
1100 PointerEventHandler::UpdateActivePointerState(mouseEvent,
1101 aTargetContent);
1102 PointerEventHandler::ImplicitlyCapturePointer(aTargetFrame, aEvent);
1103 if (mouseEvent->mInputSource != MouseEvent_Binding::MOZ_SOURCE_TOUCH) {
1104 NotifyTargetUserActivation(aEvent, aTargetContent);
1105 }
1106
1107 LightDismissOpenPopovers(aEvent, aTargetContent);
1108 }
1109 [[fallthrough]];
1110 case ePointerMove: {
1111 if (!mInTouchDrag &&
1112 PointerEventHandler::IsDragAndDropEnabled(*mouseEvent)) {
1113 GenerateDragGesture(aPresContext, mouseEvent);
1114 }
1115 // on the Mac, GenerateDragGesture() may not return until the drag
1116 // has completed and so |aTargetFrame| may have been deleted (moving
1117 // a bookmark, for example). If this is the case, however, we know
1118 // that ClearFrameRefs() has been called and it cleared out
1119 // |mCurrentTarget|. As a result, we should pass |mCurrentTarget|
1120 // into UpdateCursor().
1121 UpdateCursor(aPresContext, mouseEvent, mCurrentTarget, aStatus);
1122
1123 UpdateLastRefPointOfMouseEvent(mouseEvent);
1124 if (PointerLockManager::IsLocked()) {
1125 ResetPointerToWindowCenterWhilePointerLocked(mouseEvent);
1126 }
1127 UpdateLastPointerPosition(mouseEvent);
1128
1129 GenerateMouseEnterExit(mouseEvent);
1130 // Flush pending layout changes, so that later mouse move events
1131 // will go to the right nodes.
1132 FlushLayout(aPresContext);
1133 break;
1134 }
1135 case ePointerUp:
1136 LightDismissOpenPopovers(aEvent, aTargetContent);
1137 GenerateMouseEnterExit(mouseEvent);
1138 break;
1139 case ePointerGotCapture:
1140 GenerateMouseEnterExit(mouseEvent);
1141 break;
1142 case eDragStart:
1143 if (StaticPrefs::ui_click_hold_context_menus()) {
1144 // an external drag gesture event came in, not generated internally
1145 // by Gecko. Make sure we get rid of the click-hold timer.
1146 KillClickHoldTimer();
1147 }
1148 break;
1149 case eDragOver: {
1150 WidgetDragEvent* dragEvent = aEvent->AsDragEvent();
1151 MOZ_ASSERT(dragEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(dragEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(dragEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("dragEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1151); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dragEvent" ")"
); do { *((volatile int*)__null) = 1151; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1152 if (dragEvent->mFlags.mIsSynthesizedForTests &&
1153 allowSynthesisForTests()) {
1154 dragEvent->InitDropEffectForTests();
1155 }
1156 // Send the enter/exit events before eDrop.
1157 GenerateDragDropEnterExit(aPresContext, dragEvent);
1158 break;
1159 }
1160 case eDrop: {
1161 if (aEvent->mFlags.mIsSynthesizedForTests && allowSynthesisForTests()) {
1162 MOZ_ASSERT(aEvent->AsDragEvent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->AsDragEvent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->AsDragEvent()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->AsDragEvent()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1162); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->AsDragEvent()"
")"); do { *((volatile int*)__null) = 1162; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1163 aEvent->AsDragEvent()->InitDropEffectForTests();
1164 }
1165 break;
1166 }
1167 case eKeyPress: {
1168 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
1169 if (keyEvent->ModifiersMatchWithAccessKey(AccessKeyType::eChrome) ||
1170 keyEvent->ModifiersMatchWithAccessKey(AccessKeyType::eContent)) {
1171 // If the eKeyPress event will be sent to a remote process, this
1172 // process needs to wait reply from the remote process for checking if
1173 // preceding eKeyDown event is consumed. If preceding eKeyDown event
1174 // is consumed in the remote process, BrowserChild won't send the event
1175 // back to this process. So, only when this process receives a reply
1176 // eKeyPress event in BrowserParent, we should handle accesskey in this
1177 // process.
1178 if (IsTopLevelRemoteTarget(GetFocusedElement())) {
1179 // However, if there is no accesskey target for the key combination,
1180 // we don't need to wait reply from the remote process. Otherwise,
1181 // Mark the event as waiting reply from remote process and stop
1182 // propagation in this process.
1183 if (CheckIfEventMatchesAccessKey(keyEvent, aPresContext)) {
1184 keyEvent->StopPropagation();
1185 keyEvent->MarkAsWaitingReplyFromRemoteProcess();
1186 }
1187 }
1188 // If the event target is in this process, we can handle accesskey now
1189 // since if preceding eKeyDown event was consumed, eKeyPress event
1190 // won't be dispatched by widget. So, coming eKeyPress event means
1191 // that the preceding eKeyDown event wasn't consumed in this case.
1192 else {
1193 AutoTArray<uint32_t, 10> accessCharCodes;
1194 keyEvent->GetAccessKeyCandidates(accessCharCodes);
1195
1196 if (HandleAccessKey(keyEvent, aPresContext, accessCharCodes)) {
1197 *aStatus = nsEventStatus_eConsumeNoDefault;
1198 }
1199 }
1200 }
1201 }
1202 // then fall through...
1203 [[fallthrough]];
1204 case eKeyDown:
1205 if (aEvent->mMessage == eKeyDown) {
1206 NotifyTargetUserActivation(aEvent, aTargetContent);
1207 }
1208 [[fallthrough]];
1209 case eKeyUp: {
1210 Element* element = GetFocusedElement();
1211 if (element) {
1212 mCurrentTargetContent = element;
1213 }
1214
1215 // NOTE: Don't refer TextComposition::IsComposing() since UI Events
1216 // defines that KeyboardEvent.isComposing is true when it's
1217 // dispatched after compositionstart and compositionend.
1218 // TextComposition::IsComposing() is false even before
1219 // compositionend if there is no composing string.
1220 // And also don't expose other document's composition state.
1221 // A native IME context is typically shared by multiple documents.
1222 // So, don't use GetTextCompositionFor(nsIWidget*) here.
1223 RefPtr<TextComposition> composition =
1224 IMEStateManager::GetTextCompositionFor(aPresContext);
1225 aEvent->AsKeyboardEvent()->mIsComposing = !!composition;
1226
1227 // Widget may need to perform default action for specific keyboard
1228 // event if it's not consumed. In this case, widget has already marked
1229 // the event as "waiting reply from remote process". However, we need
1230 // to reset it if the target (focused content) isn't in a remote process
1231 // because PresShell needs to check if it's marked as so before
1232 // dispatching events into the DOM tree.
1233 if (aEvent->IsWaitingReplyFromRemoteProcess() &&
1234 !aEvent->PropagationStopped() && !IsTopLevelRemoteTarget(element)) {
1235 aEvent->ResetWaitingReplyFromRemoteProcessState();
1236 }
1237 } break;
1238 case eWheel:
1239 case eWheelOperationStart:
1240 case eWheelOperationEnd: {
1241 NS_ASSERTION(aEvent->IsTrusted(),do { if (!(aEvent->IsTrusted())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Untrusted wheel event shouldn't be here", "aEvent->IsTrusted()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1242); MOZ_PretendNoReturn(); } } while (0)
1242 "Untrusted wheel event shouldn't be here")do { if (!(aEvent->IsTrusted())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Untrusted wheel event shouldn't be here", "aEvent->IsTrusted()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1242); MOZ_PretendNoReturn(); } } while (0)
;
1243 using DeltaModeCheckingState = WidgetWheelEvent::DeltaModeCheckingState;
1244
1245 if (Element* element = GetFocusedElement()) {
1246 mCurrentTargetContent = element;
1247 }
1248
1249 if (aEvent->mMessage != eWheel) {
1250 break;
1251 }
1252
1253 WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
1254 WheelPrefs::GetInstance()->ApplyUserPrefsToDelta(wheelEvent);
1255
1256 // If we won't dispatch a DOM event for this event, nothing to do anymore.
1257 if (!wheelEvent->IsAllowedToDispatchDOMEvent()) {
1258 break;
1259 }
1260
1261 if (StaticPrefs::dom_event_wheel_deltaMode_lines_always_disabled()) {
1262 wheelEvent->mDeltaModeCheckingState = DeltaModeCheckingState::Unchecked;
1263 } else if (ShouldAlwaysUseLineDeltas()) {
1264 wheelEvent->mDeltaModeCheckingState = DeltaModeCheckingState::Checked;
1265 } else {
1266 wheelEvent->mDeltaModeCheckingState = DeltaModeCheckingState::Unknown;
1267 }
1268
1269 // Init lineOrPageDelta values for line scroll events for some devices
1270 // on some platforms which might dispatch wheel events which don't
1271 // have lineOrPageDelta values. And also, if delta values are
1272 // customized by prefs, this recomputes them.
1273 DeltaAccumulator::GetInstance()->InitLineOrPageDelta(aTargetFrame, this,
1274 wheelEvent);
1275 } break;
1276 case eSetSelection: {
1277 RefPtr<Element> focuedElement = GetFocusedElement();
1278 IMEStateManager::HandleSelectionEvent(aPresContext, focuedElement,
1279 aEvent->AsSelectionEvent());
1280 break;
1281 }
1282 case eContentCommandCut:
1283 case eContentCommandCopy:
1284 case eContentCommandPaste:
1285 case eContentCommandDelete:
1286 case eContentCommandUndo:
1287 case eContentCommandRedo:
1288 case eContentCommandPasteTransferable:
1289 case eContentCommandLookUpDictionary:
1290 DoContentCommandEvent(aEvent->AsContentCommandEvent());
1291 break;
1292 case eContentCommandInsertText:
1293 DoContentCommandInsertTextEvent(aEvent->AsContentCommandEvent());
1294 break;
1295 case eContentCommandReplaceText:
1296 DoContentCommandReplaceTextEvent(aEvent->AsContentCommandEvent());
1297 break;
1298 case eContentCommandScroll:
1299 DoContentCommandScrollEvent(aEvent->AsContentCommandEvent());
1300 break;
1301 case eCompositionStart:
1302 if (aEvent->IsTrusted()) {
1303 // If the event is trusted event, set the selected text to data of
1304 // composition event.
1305 WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent();
1306 WidgetQueryContentEvent querySelectedTextEvent(
1307 true, eQuerySelectedText, compositionEvent->mWidget);
1308 HandleQueryContentEvent(&querySelectedTextEvent);
1309 if (querySelectedTextEvent.FoundSelection()) {
1310 compositionEvent->mData = querySelectedTextEvent.mReply->DataRef();
1311 }
1312 NS_ASSERTION(querySelectedTextEvent.Succeeded(),do { if (!(querySelectedTextEvent.Succeeded())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Failed to get selected text", "querySelectedTextEvent.Succeeded()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1313); MOZ_PretendNoReturn(); } } while (0)
1313 "Failed to get selected text")do { if (!(querySelectedTextEvent.Succeeded())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Failed to get selected text", "querySelectedTextEvent.Succeeded()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1313); MOZ_PretendNoReturn(); } } while (0)
;
1314 }
1315 break;
1316 case eTouchStart:
1317 SetGestureDownPoint(aEvent->AsTouchEvent());
1318 break;
1319 case eTouchEnd:
1320 NotifyTargetUserActivation(aEvent, aTargetContent);
1321 break;
1322 default:
1323 break;
1324 }
1325 return NS_OK;
1326}
1327
1328// Returns true if this event is likely an user activation for a link or
1329// a link-like button, where modifier keys are likely be used for controlling
1330// where the link is opened.
1331//
1332// The modifiers associated with the user activation is used for controlling
1333// where the `window.open` is opened into.
1334static bool CanReflectModifiersToUserActivation(WidgetInputEvent* aEvent) {
1335 MOZ_ASSERT(aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1336); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1336; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1336 aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1336); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1336; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1337
1338 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
1339 if (keyEvent) {
1340 return keyEvent->CanReflectModifiersToUserActivation();
1341 }
1342
1343 return true;
1344}
1345
1346void EventStateManager::NotifyTargetUserActivation(WidgetEvent* aEvent,
1347 nsIContent* aTargetContent) {
1348 if (!aEvent->IsTrusted()) {
1349 return;
1350 }
1351
1352 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
1353 if (mouseEvent && !mouseEvent->IsReal()) {
1354 return;
1355 }
1356
1357 nsCOMPtr<nsINode> node = aTargetContent;
1358 if (!node) {
1359 return;
1360 }
1361
1362 Document* doc = node->OwnerDoc();
1363 if (!doc) {
1364 return;
1365 }
1366
1367 // Don't gesture activate for key events for keys which are likely
1368 // to be interaction with the browser, OS.
1369 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
1370 if (keyEvent && !keyEvent->CanUserGestureActivateTarget()) {
1371 return;
1372 }
1373
1374 // Touch gestures that end outside the drag target were touches that turned
1375 // into scroll/pan/swipe actions. We don't want to gesture activate on such
1376 // actions, we want to only gesture activate on touches that are taps.
1377 // That is, touches that end in roughly the same place that they started.
1378 if (aEvent->mMessage == eTouchEnd && aEvent->AsTouchEvent() &&
1379 IsEventOutsideDragThreshold(aEvent->AsTouchEvent())) {
1380 return;
1381 }
1382
1383 // Do not treat the click on scrollbar as a user interaction with the web
1384 // content.
1385 if (StaticPrefs::dom_user_activation_ignore_scrollbars() &&
1386 (aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown) &&
1387 aTargetContent->IsInNativeAnonymousSubtree()) {
1388 nsIContent* current = aTargetContent;
1389 do {
1390 nsIContent* root = current->GetClosestNativeAnonymousSubtreeRoot();
1391 if (!root) {
1392 break;
1393 }
1394 if (root->IsXULElement(nsGkAtoms::scrollbar)) {
1395 return;
1396 }
1397 current = root->GetParent();
1398 } while (current);
1399 }
1400
1401 MOZ_ASSERT(aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1402); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1402; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1402 aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1402); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1402; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1403 UserActivation::Modifiers modifiers;
1404 if (WidgetInputEvent* inputEvent = aEvent->AsInputEvent()) {
1405 if (CanReflectModifiersToUserActivation(inputEvent)) {
1406 if (inputEvent->IsShift()) {
1407 modifiers.SetShift();
1408 }
1409 if (inputEvent->IsMeta()) {
1410 modifiers.SetMeta();
1411 }
1412 if (inputEvent->IsControl()) {
1413 modifiers.SetControl();
1414 }
1415 if (inputEvent->IsAlt()) {
1416 modifiers.SetAlt();
1417 }
1418
1419 WidgetMouseEvent* mouseEvent = inputEvent->AsMouseEvent();
1420 if (mouseEvent) {
1421 if (mouseEvent->mButton == MouseButton::eMiddle) {
1422 modifiers.SetMiddleMouse();
1423 }
1424 }
1425 }
1426 }
1427 doc->NotifyUserGestureActivation(modifiers);
1428}
1429
1430// https://html.spec.whatwg.org/multipage/popover.html#popover-light-dismiss
1431void EventStateManager::LightDismissOpenPopovers(WidgetEvent* aEvent,
1432 nsIContent* aTargetContent) {
1433 MOZ_ASSERT(aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == ePointerDown || aEvent->mMessage
== ePointerUp)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
" (" "Light dismiss must be called for pointer up/down only"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1434); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
") (" "Light dismiss must be called for pointer up/down only"
")"); do { *((volatile int*)__null) = 1434; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1434 "Light dismiss must be called for pointer up/down only")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == ePointerDown || aEvent->mMessage
== ePointerUp)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
" (" "Light dismiss must be called for pointer up/down only"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1434); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
") (" "Light dismiss must be called for pointer up/down only"
")"); do { *((volatile int*)__null) = 1434; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1435
1436 if (!StaticPrefs::dom_element_popover_enabled() || !aEvent->IsTrusted() ||
1437 !aTargetContent) {
1438 return;
1439 }
1440
1441 Element* topmostPopover = aTargetContent->OwnerDoc()->GetTopmostAutoPopover();
1442 if (!topmostPopover) {
1443 return;
1444 }
1445
1446 // Pointerdown: set document's popover pointerdown target to the result of
1447 // running topmost clicked popover given target.
1448 if (aEvent->mMessage == ePointerDown) {
1449 mPopoverPointerDownTarget = aTargetContent->GetTopmostClickedPopover();
1450 return;
1451 }
1452
1453 // Pointerup: hide open popovers.
1454 RefPtr<nsINode> ancestor = aTargetContent->GetTopmostClickedPopover();
1455 bool sameTarget = mPopoverPointerDownTarget == ancestor;
1456 mPopoverPointerDownTarget = nullptr;
1457 if (!sameTarget) {
1458 return;
1459 }
1460
1461 if (!ancestor) {
1462 ancestor = aTargetContent->OwnerDoc();
1463 }
1464 RefPtr<Document> doc(ancestor->OwnerDoc());
1465 doc->HideAllPopoversUntil(*ancestor, false, true);
1466}
1467
1468already_AddRefed<EventStateManager> EventStateManager::ESMFromContentOrThis(
1469 nsIContent* aContent) {
1470 if (aContent) {
1471 PresShell* presShell = aContent->OwnerDoc()->GetPresShell();
1472 if (presShell) {
1473 nsPresContext* prescontext = presShell->GetPresContext();
1474 if (prescontext) {
1475 RefPtr<EventStateManager> esm = prescontext->EventStateManager();
1476 if (esm) {
1477 return esm.forget();
1478 }
1479 }
1480 }
1481 }
1482
1483 RefPtr<EventStateManager> esm = this;
1484 return esm.forget();
1485}
1486
1487EventStateManager::LastMouseDownInfo& EventStateManager::GetLastMouseDownInfo(
1488 int16_t aButton) {
1489 switch (aButton) {
1490 case MouseButton::ePrimary:
1491 return mLastLeftMouseDownInfo;
1492 case MouseButton::eMiddle:
1493 return mLastMiddleMouseDownInfo;
1494 case MouseButton::eSecondary:
1495 return mLastRightMouseDownInfo;
1496 default:
1497 MOZ_ASSERT_UNREACHABLE("This button shouldn't use this method")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"This button shouldn't use this method" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1497); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "This button shouldn't use this method"
")"); do { *((volatile int*)__null) = 1497; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1498 return mLastLeftMouseDownInfo;
1499 }
1500}
1501
1502void EventStateManager::HandleQueryContentEvent(
1503 WidgetQueryContentEvent* aEvent) {
1504 switch (aEvent->mMessage) {
1505 case eQuerySelectedText:
1506 case eQueryTextContent:
1507 case eQueryCaretRect:
1508 case eQueryTextRect:
1509 case eQueryEditorRect:
1510 if (!IsTargetCrossProcess(aEvent)) {
1511 break;
1512 }
1513 // Will not be handled locally, remote the event
1514 GetCrossProcessTarget()->HandleQueryContentEvent(*aEvent);
1515 return;
1516 // Following events have not been supported in e10s mode yet.
1517 case eQueryContentState:
1518 case eQuerySelectionAsTransferable:
1519 case eQueryCharacterAtPoint:
1520 case eQueryDOMWidgetHittest:
1521 case eQueryTextRectArray:
1522 break;
1523 default:
1524 return;
1525 }
1526
1527 // If there is an IMEContentObserver, we need to handle QueryContentEvent
1528 // with it.
1529 if (mIMEContentObserver) {
1530 RefPtr<IMEContentObserver> contentObserver = mIMEContentObserver;
1531 contentObserver->HandleQueryContentEvent(aEvent);
1532 return;
1533 }
1534
1535 ContentEventHandler handler(mPresContext);
1536 handler.HandleQueryContentEvent(aEvent);
1537}
1538
1539static AccessKeyType GetAccessKeyTypeFor(nsISupports* aDocShell) {
1540 nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(aDocShell));
1541 if (!treeItem) {
1542 return AccessKeyType::eNone;
1543 }
1544
1545 switch (treeItem->ItemType()) {
1546 case nsIDocShellTreeItem::typeChrome:
1547 return AccessKeyType::eChrome;
1548 case nsIDocShellTreeItem::typeContent:
1549 return AccessKeyType::eContent;
1550 default:
1551 return AccessKeyType::eNone;
1552 }
1553}
1554
1555static bool IsAccessKeyTarget(Element* aElement, nsAString& aKey) {
1556 // Use GetAttr because we want Unicode case=insensitive matching
1557 // XXXbz shouldn't this be case-sensitive, per spec?
1558 nsString contentKey;
1559 if (!aElement || !aElement->GetAttr(nsGkAtoms::accesskey, contentKey) ||
1560 !contentKey.Equals(aKey, nsCaseInsensitiveStringComparator)) {
1561 return false;
1562 }
1563
1564 if (!aElement->IsXULElement()) {
1565 return true;
1566 }
1567
1568 // For XUL we do visibility checks.
1569 nsIFrame* frame = aElement->GetPrimaryFrame();
1570 if (!frame) {
1571 return false;
1572 }
1573
1574 if (frame->IsFocusable()) {
1575 return true;
1576 }
1577
1578 if (!frame->IsVisibleConsideringAncestors()) {
1579 return false;
1580 }
1581
1582 // XUL controls can be activated.
1583 nsCOMPtr<nsIDOMXULControlElement> control = aElement->AsXULControl();
1584 if (control) {
1585 return true;
1586 }
1587
1588 // XUL label elements are never focusable, so we need to check for them
1589 // explicitly before giving up.
1590 if (aElement->IsXULElement(nsGkAtoms::label)) {
1591 return true;
1592 }
1593
1594 return false;
1595}
1596
1597bool EventStateManager::CheckIfEventMatchesAccessKey(
1598 WidgetKeyboardEvent* aEvent, nsPresContext* aPresContext) {
1599 AutoTArray<uint32_t, 10> accessCharCodes;
1600 aEvent->GetAccessKeyCandidates(accessCharCodes);
1601 return WalkESMTreeToHandleAccessKey(aEvent, aPresContext, accessCharCodes,
1602 nullptr, eAccessKeyProcessingNormal,
1603 false);
1604}
1605
1606bool EventStateManager::LookForAccessKeyAndExecute(
1607 nsTArray<uint32_t>& aAccessCharCodes, bool aIsTrustedEvent, bool aIsRepeat,
1608 bool aExecute) {
1609 int32_t count, start = -1;
1610 if (Element* focusedElement = GetFocusedElement()) {
1611 start = mAccessKeys.IndexOf(focusedElement);
1612 if (start == -1 && focusedElement->IsInNativeAnonymousSubtree()) {
1613 start = mAccessKeys.IndexOf(Element::FromNodeOrNull(
1614 focusedElement->GetClosestNativeAnonymousSubtreeRootParentOrHost()));
1615 }
1616 }
1617 RefPtr<Element> element;
1618 int32_t length = mAccessKeys.Count();
1619 for (uint32_t i = 0; i < aAccessCharCodes.Length(); ++i) {
1620 uint32_t ch = aAccessCharCodes[i];
1621 nsAutoString accessKey;
1622 AppendUCS4ToUTF16(ch, accessKey);
1623 for (count = 1; count <= length; ++count) {
1624 // mAccessKeys always stores Element instances.
1625 MOZ_DIAGNOSTIC_ASSERT(length == mAccessKeys.Count())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(length == mAccessKeys.Count())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(length == mAccessKeys.Count(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("length == mAccessKeys.Count()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1625); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "length == mAccessKeys.Count()"
")"); do { *((volatile int*)__null) = 1625; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1626 element = mAccessKeys[(start + count) % length];
1627 if (IsAccessKeyTarget(element, accessKey)) {
1628 if (!aExecute) {
1629 return true;
1630 }
1631 Document* doc = element->OwnerDoc();
1632 const bool shouldActivate = [&] {
1633 if (!StaticPrefs::accessibility_accesskeycausesactivation()) {
1634 return false;
1635 }
1636 if (aIsRepeat && nsContentUtils::IsChromeDoc(doc)) {
1637 return false;
1638 }
1639
1640 // XXXedgar, Bug 1700646, maybe we could use other data structure to
1641 // make searching target with same accesskey easier, and current setup
1642 // could not ensure we cycle the target with tree order.
1643 int32_t j = 0;
1644 while (++j < length) {
1645 Element* el = mAccessKeys[(start + count + j) % length];
1646 if (IsAccessKeyTarget(el, accessKey)) {
1647 return false;
1648 }
1649 }
1650 return true;
1651 }();
1652
1653 // TODO(bug 1641171): This shouldn't be needed if we considered the
1654 // accesskey combination properly.
1655 if (aIsTrustedEvent) {
1656 doc->NotifyUserGestureActivation();
1657 }
1658
1659 auto result =
1660 element->PerformAccesskey(shouldActivate, aIsTrustedEvent);
1661 if (result.isOk()) {
1662 if (result.unwrap() && aIsTrustedEvent) {
1663 // If this is a child process, inform the parent that we want the
1664 // focus, but pass false since we don't want to change the window
1665 // order.
1666 nsIDocShell* docShell = mPresContext->GetDocShell();
1667 nsCOMPtr<nsIBrowserChild> child =
1668 docShell ? docShell->GetBrowserChild() : nullptr;
1669 if (child) {
1670 child->SendRequestFocus(false, CallerType::System);
1671 }
1672 }
1673 return true;
1674 }
1675 }
1676 }
1677 }
1678 return false;
1679}
1680
1681// static
1682void EventStateManager::GetAccessKeyLabelPrefix(Element* aElement,
1683 nsAString& aPrefix) {
1684 aPrefix.Truncate();
1685 nsAutoString separator, modifierText;
1686 nsContentUtils::GetModifierSeparatorText(separator);
1687
1688 AccessKeyType accessKeyType =
1689 GetAccessKeyTypeFor(aElement->OwnerDoc()->GetDocShell());
1690 if (accessKeyType == AccessKeyType::eNone) {
1691 return;
1692 }
1693 Modifiers modifiers = WidgetKeyboardEvent::AccessKeyModifiers(accessKeyType);
1694 if (modifiers == MODIFIER_NONE) {
1695 return;
1696 }
1697
1698 if (modifiers & MODIFIER_CONTROL) {
1699 nsContentUtils::GetControlText(modifierText);
1700 aPrefix.Append(modifierText + separator);
1701 }
1702 if (modifiers & MODIFIER_META) {
1703 nsContentUtils::GetCommandOrWinText(modifierText);
1704 aPrefix.Append(modifierText + separator);
1705 }
1706 if (modifiers & MODIFIER_ALT) {
1707 nsContentUtils::GetAltText(modifierText);
1708 aPrefix.Append(modifierText + separator);
1709 }
1710 if (modifiers & MODIFIER_SHIFT) {
1711 nsContentUtils::GetShiftText(modifierText);
1712 aPrefix.Append(modifierText + separator);
1713 }
1714}
1715
1716struct MOZ_STACK_CLASS AccessKeyInfo {
1717 WidgetKeyboardEvent* event;
1718 nsTArray<uint32_t>& charCodes;
1719
1720 AccessKeyInfo(WidgetKeyboardEvent* aEvent, nsTArray<uint32_t>& aCharCodes)
1721 : event(aEvent), charCodes(aCharCodes) {}
1722};
1723
1724bool EventStateManager::WalkESMTreeToHandleAccessKey(
1725 WidgetKeyboardEvent* aEvent, nsPresContext* aPresContext,
1726 nsTArray<uint32_t>& aAccessCharCodes, nsIDocShellTreeItem* aBubbledFrom,
1727 ProcessingAccessKeyState aAccessKeyState, bool aExecute) {
1728 EnsureDocument(mPresContext);
1729 nsCOMPtr<nsIDocShell> docShell = aPresContext->GetDocShell();
1730 if (NS_WARN_IF(!docShell)NS_warn_if_impl(!docShell, "!docShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1730)
|| NS_WARN_IF(!mDocument)NS_warn_if_impl(!mDocument, "!mDocument", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1730)
) {
1731 return false;
1732 }
1733 AccessKeyType accessKeyType = GetAccessKeyTypeFor(docShell);
1734 if (accessKeyType == AccessKeyType::eNone) {
1735 return false;
1736 }
1737 // Alt or other accesskey modifier is down, we may need to do an accesskey.
1738 if (mAccessKeys.Count() > 0 &&
1739 aEvent->ModifiersMatchWithAccessKey(accessKeyType)) {
1740 // Someone registered an accesskey. Find and activate it.
1741 if (LookForAccessKeyAndExecute(aAccessCharCodes, aEvent->IsTrusted(),
1742 aEvent->mIsRepeat, aExecute)) {
1743 return true;
1744 }
1745 }
1746
1747 int32_t childCount;
1748 docShell->GetInProcessChildCount(&childCount);
1749 for (int32_t counter = 0; counter < childCount; counter++) {
1750 // Not processing the child which bubbles up the handling
1751 nsCOMPtr<nsIDocShellTreeItem> subShellItem;
1752 docShell->GetInProcessChildAt(counter, getter_AddRefs(subShellItem));
1753 if (aAccessKeyState == eAccessKeyProcessingUp &&
1754 subShellItem == aBubbledFrom) {
1755 continue;
1756 }
1757
1758 nsCOMPtr<nsIDocShell> subDS = do_QueryInterface(subShellItem);
1759 if (subDS && IsShellVisible(subDS)) {
1760 // Guarantee subPresShell lifetime while we're handling access key
1761 // since somebody may assume that it won't be deleted before the
1762 // corresponding nsPresContext and EventStateManager.
1763 RefPtr<PresShell> subPresShell = subDS->GetPresShell();
1764
1765 // Docshells need not have a presshell (eg. display:none
1766 // iframes, docshells in transition between documents, etc).
1767 if (!subPresShell) {
1768 // Oh, well. Just move on to the next child
1769 continue;
1770 }
1771
1772 RefPtr<nsPresContext> subPresContext = subPresShell->GetPresContext();
1773
1774 RefPtr<EventStateManager> esm =
1775 static_cast<EventStateManager*>(subPresContext->EventStateManager());
1776
1777 if (esm && esm->WalkESMTreeToHandleAccessKey(
1778 aEvent, subPresContext, aAccessCharCodes, nullptr,
1779 eAccessKeyProcessingDown, aExecute)) {
1780 return true;
1781 }
1782 }
1783 } // if end . checking all sub docshell ends here.
1784
1785 // bubble up the process to the parent docshell if necessary
1786 if (eAccessKeyProcessingDown != aAccessKeyState) {
1787 nsCOMPtr<nsIDocShellTreeItem> parentShellItem;
1788 docShell->GetInProcessParent(getter_AddRefs(parentShellItem));
1789 nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parentShellItem);
1790 if (parentDS) {
1791 // Guarantee parentPresShell lifetime while we're handling access key
1792 // since somebody may assume that it won't be deleted before the
1793 // corresponding nsPresContext and EventStateManager.
1794 RefPtr<PresShell> parentPresShell = parentDS->GetPresShell();
1795 NS_ASSERTION(parentPresShell,do { if (!(parentPresShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Our PresShell exists but the parent's does not?", "parentPresShell"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1796); MOZ_PretendNoReturn(); } } while (0)
1796 "Our PresShell exists but the parent's does not?")do { if (!(parentPresShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Our PresShell exists but the parent's does not?", "parentPresShell"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1796); MOZ_PretendNoReturn(); } } while (0)
;
1797
1798 RefPtr<nsPresContext> parentPresContext =
1799 parentPresShell->GetPresContext();
1800 NS_ASSERTION(parentPresContext, "PresShell without PresContext")do { if (!(parentPresContext)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "PresShell without PresContext", "parentPresContext", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1800); MOZ_PretendNoReturn(); } } while (0)
;
1801
1802 RefPtr<EventStateManager> esm = static_cast<EventStateManager*>(
1803 parentPresContext->EventStateManager());
1804 if (esm && esm->WalkESMTreeToHandleAccessKey(
1805 aEvent, parentPresContext, aAccessCharCodes, docShell,
1806 eAccessKeyProcessingDown, aExecute)) {
1807 return true;
1808 }
1809 }
1810 } // if end. bubble up process
1811
1812 // If the content access key modifier is pressed, try remote children
1813 if (aExecute &&
1814 aEvent->ModifiersMatchWithAccessKey(AccessKeyType::eContent) &&
1815 mDocument && mDocument->GetWindow()) {
1816 // If the focus is currently on a node with a BrowserParent, the key event
1817 // should've gotten forwarded to the child process and HandleAccessKey
1818 // called from there.
1819 if (BrowserParent::GetFrom(GetFocusedElement())) {
1820 // If access key may be only in remote contents, this method won't handle
1821 // access key synchronously. In this case, only reply event should reach
1822 // here.
1823 MOZ_ASSERT(aEvent->IsHandledInRemoteProcess() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->IsHandledInRemoteProcess() || !aEvent->
IsWaitingReplyFromRemoteProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->IsHandledInRemoteProcess
() || !aEvent->IsWaitingReplyFromRemoteProcess()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aEvent->IsHandledInRemoteProcess() || !aEvent->IsWaitingReplyFromRemoteProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1824); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsHandledInRemoteProcess() || !aEvent->IsWaitingReplyFromRemoteProcess()"
")"); do { *((volatile int*)__null) = 1824; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1824 !aEvent->IsWaitingReplyFromRemoteProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->IsHandledInRemoteProcess() || !aEvent->
IsWaitingReplyFromRemoteProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->IsHandledInRemoteProcess
() || !aEvent->IsWaitingReplyFromRemoteProcess()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aEvent->IsHandledInRemoteProcess() || !aEvent->IsWaitingReplyFromRemoteProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1824); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsHandledInRemoteProcess() || !aEvent->IsWaitingReplyFromRemoteProcess()"
")"); do { *((volatile int*)__null) = 1824; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1825 }
1826 // If focus is somewhere else, then we need to check the remote children.
1827 // However, if the event has already been handled in a remote process,
1828 // then, focus is moved from the remote process after posting the event.
1829 // In such case, we shouldn't retry to handle access keys in remote
1830 // processes.
1831 else if (!aEvent->IsHandledInRemoteProcess()) {
1832 AccessKeyInfo accessKeyInfo(aEvent, aAccessCharCodes);
1833 nsContentUtils::CallOnAllRemoteChildren(
1834 mDocument->GetWindow(),
1835 [&accessKeyInfo](BrowserParent* aBrowserParent) -> CallState {
1836 // Only forward accesskeys for the active tab.
1837 if (aBrowserParent->GetDocShellIsActive()) {
1838 // Even if there is no target for the accesskey in this process,
1839 // the event may match with a content accesskey. If so, the
1840 // keyboard event should be handled with reply event for
1841 // preventing double action. (e.g., Alt+Shift+F on Windows may
1842 // focus a content in remote and open "File" menu.)
1843 accessKeyInfo.event->StopPropagation();
1844 accessKeyInfo.event->MarkAsWaitingReplyFromRemoteProcess();
1845 aBrowserParent->HandleAccessKey(*accessKeyInfo.event,
1846 accessKeyInfo.charCodes);
1847 return CallState::Stop;
1848 }
1849
1850 return CallState::Continue;
1851 });
1852 }
1853 }
1854
1855 return false;
1856} // end of HandleAccessKey
1857
1858static BrowserParent* GetBrowserParentAncestor(BrowserParent* aBrowserParent) {
1859 MOZ_ASSERT(aBrowserParent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aBrowserParent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aBrowserParent))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aBrowserParent"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1859); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aBrowserParent"
")"); do { *((volatile int*)__null) = 1859; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1860
1861 BrowserBridgeParent* bbp = aBrowserParent->GetBrowserBridgeParent();
1862 if (!bbp) {
1863 return nullptr;
1864 }
1865
1866 return bbp->Manager();
1867}
1868
1869static void DispatchCrossProcessMouseExitEvents(WidgetMouseEvent* aMouseEvent,
1870 BrowserParent* aRemoteTarget,
1871 BrowserParent* aStopAncestor,
1872 bool aIsReallyExit) {
1873 MOZ_ASSERT(aMouseEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseEvent))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aMouseEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1873); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseEvent"
")"); do { *((volatile int*)__null) = 1873; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1874 MOZ_ASSERT(aRemoteTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRemoteTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aRemoteTarget))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aRemoteTarget",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1874); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRemoteTarget"
")"); do { *((volatile int*)__null) = 1874; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1875 MOZ_ASSERT(aRemoteTarget != aStopAncestor)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRemoteTarget != aStopAncestor)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aRemoteTarget != aStopAncestor
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aRemoteTarget != aStopAncestor", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1875); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRemoteTarget != aStopAncestor"
")"); do { *((volatile int*)__null) = 1875; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1876 MOZ_ASSERT_IF(aStopAncestor, nsContentUtils::GetCommonBrowserParentAncestor(do { if (aStopAncestor) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(nsContentUtils::GetCommonBrowserParentAncestor
( aRemoteTarget, aStopAncestor))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nsContentUtils::GetCommonBrowserParentAncestor
( aRemoteTarget, aStopAncestor)))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("nsContentUtils::GetCommonBrowserParentAncestor( aRemoteTarget, aStopAncestor)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::GetCommonBrowserParentAncestor( aRemoteTarget, aStopAncestor)"
")"); do { *((volatile int*)__null) = 1877; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1877 aRemoteTarget, aStopAncestor))do { if (aStopAncestor) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(nsContentUtils::GetCommonBrowserParentAncestor
( aRemoteTarget, aStopAncestor))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nsContentUtils::GetCommonBrowserParentAncestor
( aRemoteTarget, aStopAncestor)))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("nsContentUtils::GetCommonBrowserParentAncestor( aRemoteTarget, aStopAncestor)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::GetCommonBrowserParentAncestor( aRemoteTarget, aStopAncestor)"
")"); do { *((volatile int*)__null) = 1877; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1878
1879 while (aRemoteTarget != aStopAncestor) {
1880 UniquePtr<WidgetMouseEvent> mouseExitEvent =
1881 CreateMouseOrPointerWidgetEvent(aMouseEvent, eMouseExitFromWidget,
1882 aMouseEvent->mRelatedTarget);
1883 mouseExitEvent->mExitFrom =
1884 Some(aIsReallyExit ? WidgetMouseEvent::ePuppet
1885 : WidgetMouseEvent::ePuppetParentToPuppetChild);
1886 aRemoteTarget->SendRealMouseEvent(*mouseExitEvent);
1887
1888 aRemoteTarget = GetBrowserParentAncestor(aRemoteTarget);
1889 }
1890}
1891
1892void EventStateManager::DispatchCrossProcessEvent(WidgetEvent* aEvent,
1893 BrowserParent* aRemoteTarget,
1894 nsEventStatus* aStatus) {
1895 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1895); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 1895; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1
Assuming 'aEvent' is non-null
2
Taking false branch
3
Loop condition is false. Exiting loop
1896 MOZ_ASSERT(aRemoteTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRemoteTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aRemoteTarget))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aRemoteTarget",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1896); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRemoteTarget"
")"); do { *((volatile int*)__null) = 1896; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4
Assuming 'aRemoteTarget' is non-null
5
Taking false branch
6
Loop condition is false. Exiting loop
1897 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1897); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 1897; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7
Assuming 'aStatus' is non-null
8
Taking false branch
9
Loop condition is false. Exiting loop
1898
1899 BrowserParent* remote = aRemoteTarget;
1900
1901 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
10
'mouseEvent' initialized here
1902 bool isContextMenuKey = mouseEvent && mouseEvent->IsContextMenuKeyEvent();
11
Assuming 'mouseEvent' is null
1903 if (aEvent->mClass == eKeyboardEventClass || isContextMenuKey
12.1
'isContextMenuKey' is false
) {
12
Assuming field 'mClass' is not equal to eKeyboardEventClass
13
Taking false branch
1904 // APZ attaches a LayersId to hit-testable events, for keyboard events,
1905 // we use focus.
1906 BrowserParent* preciseRemote = BrowserParent::GetFocused();
1907 if (preciseRemote) {
1908 remote = preciseRemote;
1909 }
1910 // else there is a race between layout and focus tracking,
1911 // so fall back to delivering the event to the topmost child process.
1912 } else if (aEvent->mLayersId.IsValid()) {
14
Taking false branch
1913 BrowserParent* preciseRemote =
1914 BrowserParent::GetBrowserParentFromLayersId(aEvent->mLayersId);
1915 if (preciseRemote) {
1916 remote = preciseRemote;
1917 }
1918 // else there is a race between APZ and the LayersId to BrowserParent
1919 // mapping, so fall back to delivering the event to the topmost child
1920 // process.
1921 }
1922
1923 MOZ_ASSERT(aEvent->mMessage != ePointerClick)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage != ePointerClick)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage != ePointerClick
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aEvent->mMessage != ePointerClick", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1923); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage != ePointerClick"
")"); do { *((volatile int*)__null) = 1923; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
15
Assuming field 'mMessage' is not equal to ePointerClick
16
Taking false branch
17
Loop condition is false. Exiting loop
1924 MOZ_ASSERT(aEvent->mMessage != ePointerAuxClick)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage != ePointerAuxClick)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage != ePointerAuxClick))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage != ePointerAuxClick"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1924); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage != ePointerAuxClick"
")"); do { *((volatile int*)__null) = 1924; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
18
Assuming field 'mMessage' is not equal to ePointerAuxClick
19
Taking false branch
20
Loop condition is false. Exiting loop
1925
1926 // SendReal* will transform the coordinate to the child process coordinate
1927 // space. So restore the coordinate after the event has been dispatched to the
1928 // child process to avoid using the transformed coordinate afterward.
1929 AutoRestore<LayoutDeviceIntPoint> restore(aEvent->mRefPoint);
1930 switch (aEvent->mClass) {
21
Control jumps to 'case eMouseEventClass:' at line 1934
1931 case ePointerEventClass:
1932 MOZ_ASSERT(aEvent->mMessage == eContextMenu)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eContextMenu)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eContextMenu
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aEvent->mMessage == eContextMenu", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1932); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eContextMenu"
")"); do { *((volatile int*)__null) = 1932; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1933 [[fallthrough]];
1934 case eMouseEventClass: {
1935 BrowserParent* oldRemote = BrowserParent::GetLastMouseRemoteTarget();
1936
1937 // If this is a eMouseExitFromWidget event, need to redirect the event to
1938 // the last remote and and notify all its ancestors about the exit, if
1939 // any.
1940 if (mouseEvent->mMessage == eMouseExitFromWidget) {
22
Access to field 'mMessage' results in a dereference of a null pointer (loaded from variable 'mouseEvent')
1941 MOZ_ASSERT(mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mouseEvent->mExitFrom.value() == WidgetMouseEvent
::ePuppet)>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(mouseEvent->mExitFrom.value() ==
WidgetMouseEvent::ePuppet))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1941); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
")"); do { *((volatile int*)__null) = 1941; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1942 MOZ_ASSERT(mouseEvent->mReason == WidgetMouseEvent::eReal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mouseEvent->mReason == WidgetMouseEvent::eReal)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mouseEvent->mReason == WidgetMouseEvent::eReal)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("mouseEvent->mReason == WidgetMouseEvent::eReal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1942); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mReason == WidgetMouseEvent::eReal"
")"); do { *((volatile int*)__null) = 1942; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1943 MOZ_ASSERT(!mouseEvent->mLayersId.IsValid())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mouseEvent->mLayersId.IsValid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mouseEvent->mLayersId.IsValid
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mouseEvent->mLayersId.IsValid()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1943); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mouseEvent->mLayersId.IsValid()"
")"); do { *((volatile int*)__null) = 1943; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1944 MOZ_ASSERT(remote->GetBrowserHost())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(remote->GetBrowserHost())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(remote->GetBrowserHost())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("remote->GetBrowserHost()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1944); AnnotateMozCrashReason("MOZ_ASSERT" "(" "remote->GetBrowserHost()"
")"); do { *((volatile int*)__null) = 1944; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1945
1946 if (oldRemote && oldRemote != remote) {
1947 Unused << NS_WARN_IF(nsContentUtils::GetCommonBrowserParentAncestor(NS_warn_if_impl(nsContentUtils::GetCommonBrowserParentAncestor
( remote, oldRemote) != remote, "nsContentUtils::GetCommonBrowserParentAncestor( remote, oldRemote) != remote"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1948)
1948 remote, oldRemote) != remote)NS_warn_if_impl(nsContentUtils::GetCommonBrowserParentAncestor
( remote, oldRemote) != remote, "nsContentUtils::GetCommonBrowserParentAncestor( remote, oldRemote) != remote"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1948)
;
1949 remote = oldRemote;
1950 }
1951
1952 DispatchCrossProcessMouseExitEvents(mouseEvent, remote, nullptr, true);
1953 return;
1954 }
1955
1956 if (BrowserParent* pointerLockedRemote =
1957 PointerLockManager::GetLockedRemoteTarget()) {
1958 remote = pointerLockedRemote;
1959 } else if (BrowserParent* pointerCapturedRemote =
1960 PointerEventHandler::GetPointerCapturingRemoteTarget(
1961 mouseEvent->pointerId)) {
1962 remote = pointerCapturedRemote;
1963 } else if (BrowserParent* capturingRemote =
1964 PresShell::GetCapturingRemoteTarget()) {
1965 remote = capturingRemote;
1966 }
1967
1968 // If a mouse is over a remote target A, and then moves to
1969 // remote target B, we'd deliver the event directly to remote target B
1970 // after the moving, A would never get notified that the mouse left.
1971 // So we generate a exit event to notify A after the move.
1972 // XXXedgar, if the synthesized mouse events could deliver to the correct
1973 // process directly (see
1974 // https://bugzilla.mozilla.org/show_bug.cgi?id=1549355), we probably
1975 // don't need to check mReason then.
1976 if (mouseEvent->mReason == WidgetMouseEvent::eReal &&
1977 remote != oldRemote) {
1978 MOZ_ASSERT(mouseEvent->mMessage != eMouseExitFromWidget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mouseEvent->mMessage != eMouseExitFromWidget)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mouseEvent->mMessage != eMouseExitFromWidget))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mouseEvent->mMessage != eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1978); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mMessage != eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 1978; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1979 if (oldRemote) {
1980 BrowserParent* commonAncestor =
1981 nsContentUtils::GetCommonBrowserParentAncestor(remote, oldRemote);
1982 if (commonAncestor == oldRemote) {
1983 // Mouse moves to the inner OOP frame, it is not a really exit.
1984 DispatchCrossProcessMouseExitEvents(
1985 mouseEvent, GetBrowserParentAncestor(remote),
1986 GetBrowserParentAncestor(commonAncestor), false);
1987 } else if (commonAncestor == remote) {
1988 // Mouse moves to the outer OOP frame, it is a really exit.
1989 DispatchCrossProcessMouseExitEvents(mouseEvent, oldRemote,
1990 commonAncestor, true);
1991 } else {
1992 // Mouse moves to OOP frame in other subtree, it is a really exit,
1993 // need to notify all its ancestors before common ancestor about the
1994 // exit.
1995 DispatchCrossProcessMouseExitEvents(mouseEvent, oldRemote,
1996 commonAncestor, true);
1997 if (commonAncestor) {
1998 UniquePtr<WidgetMouseEvent> mouseExitEvent =
1999 CreateMouseOrPointerWidgetEvent(mouseEvent,
2000 eMouseExitFromWidget,
2001 mouseEvent->mRelatedTarget);
2002 mouseExitEvent->mExitFrom =
2003 Some(WidgetMouseEvent::ePuppetParentToPuppetChild);
2004 commonAncestor->SendRealMouseEvent(*mouseExitEvent);
2005 }
2006 }
2007 }
2008
2009 if (mouseEvent->mMessage != eMouseExitFromWidget &&
2010 mouseEvent->mMessage != eMouseEnterIntoWidget) {
2011 // This is to make cursor would be updated correctly.
2012 remote->MouseEnterIntoWidget();
2013 }
2014 }
2015
2016 remote->SendRealMouseEvent(*mouseEvent);
2017 return;
2018 }
2019 case eKeyboardEventClass: {
2020 auto* keyboardEvent = aEvent->AsKeyboardEvent();
2021 if (aEvent->mMessage == eKeyUp) {
2022 HandleKeyUpInteraction(keyboardEvent);
2023 }
2024 remote->SendRealKeyEvent(*keyboardEvent);
2025 return;
2026 }
2027 case eWheelEventClass: {
2028 if (BrowserParent* pointerLockedRemote =
2029 PointerLockManager::GetLockedRemoteTarget()) {
2030 remote = pointerLockedRemote;
2031 }
2032 remote->SendMouseWheelEvent(*aEvent->AsWheelEvent());
2033 return;
2034 }
2035 case eTouchEventClass: {
2036 // Let the child process synthesize a mouse event if needed, and
2037 // ensure we don't synthesize one in this process.
2038 *aStatus = nsEventStatus_eConsumeNoDefault;
2039 remote->SendRealTouchEvent(*aEvent->AsTouchEvent());
2040 return;
2041 }
2042 case eDragEventClass: {
2043 RefPtr<BrowserParent> browserParent = remote;
2044 browserParent->MaybeInvokeDragSession(aEvent->mMessage);
2045
2046 RefPtr<nsIWidget> widget = browserParent->GetTopLevelWidget();
2047 nsCOMPtr<nsIDragSession> dragSession =
2048 nsContentUtils::GetDragSession(widget);
2049 uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
2050 uint32_t action = nsIDragService::DRAGDROP_ACTION_NONE;
2051 nsCOMPtr<nsIPrincipal> principal;
2052 nsCOMPtr<nsIContentSecurityPolicy> csp;
2053
2054 if (dragSession) {
2055 dragSession->DragEventDispatchedToChildProcess();
2056 dragSession->GetDragAction(&action);
2057 dragSession->GetTriggeringPrincipal(getter_AddRefs(principal));
2058 dragSession->GetCsp(getter_AddRefs(csp));
2059 RefPtr<DataTransfer> initialDataTransfer =
2060 dragSession->GetDataTransfer();
2061 if (initialDataTransfer) {
2062 dropEffect = initialDataTransfer->DropEffectInt();
2063 }
2064 }
2065
2066 browserParent->SendRealDragEvent(*aEvent->AsDragEvent(), action,
2067 dropEffect, principal, csp);
2068 return;
2069 }
2070 default: {
2071 MOZ_CRASH("Attempt to send non-whitelisted event?")do { do { } while (false); MOZ_ReportCrash("" "Attempt to send non-whitelisted event?"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2071); AnnotateMozCrashReason("MOZ_CRASH(" "Attempt to send non-whitelisted event?"
")"); do { *((volatile int*)__null) = 2071; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2072 }
2073 }
2074}
2075
2076bool EventStateManager::IsRemoteTarget(nsIContent* target) {
2077 return BrowserParent::GetFrom(target) || BrowserBridgeChild::GetFrom(target);
2078}
2079
2080bool EventStateManager::IsTopLevelRemoteTarget(nsIContent* target) {
2081 return !!BrowserParent::GetFrom(target);
2082}
2083
2084bool EventStateManager::HandleCrossProcessEvent(WidgetEvent* aEvent,
2085 nsEventStatus* aStatus) {
2086 if (!aEvent->CanBeSentToRemoteProcess()) {
2087 return false;
2088 }
2089
2090 MOZ_ASSERT(!aEvent->HasBeenPostedToRemoteProcess(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEvent->HasBeenPostedToRemoteProcess())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aEvent->HasBeenPostedToRemoteProcess()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aEvent->HasBeenPostedToRemoteProcess()"
" (" "Why do we need to post same event to remote processes again?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2091); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aEvent->HasBeenPostedToRemoteProcess()"
") (" "Why do we need to post same event to remote processes again?"
")"); do { *((volatile int*)__null) = 2091; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2091 "Why do we need to post same event to remote processes again?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEvent->HasBeenPostedToRemoteProcess())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aEvent->HasBeenPostedToRemoteProcess()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aEvent->HasBeenPostedToRemoteProcess()"
" (" "Why do we need to post same event to remote processes again?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2091); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aEvent->HasBeenPostedToRemoteProcess()"
") (" "Why do we need to post same event to remote processes again?"
")"); do { *((volatile int*)__null) = 2091; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2092
2093 // Collect the remote event targets we're going to forward this
2094 // event to.
2095 //
2096 // NB: the elements of |remoteTargets| must be unique, for correctness.
2097 AutoTArray<RefPtr<BrowserParent>, 1> remoteTargets;
2098 if (aEvent->mClass != eTouchEventClass || aEvent->mMessage == eTouchStart) {
2099 // If this event only has one target, and it's remote, add it to
2100 // the array.
2101 nsIFrame* frame = aEvent->mMessage == eDragExit
2102 ? sLastDragOverFrame.GetFrame()
2103 : GetEventTarget();
2104 nsIContent* target = frame ? frame->GetContent() : nullptr;
2105 if (BrowserParent* remoteTarget = BrowserParent::GetFrom(target)) {
2106 remoteTargets.AppendElement(remoteTarget);
2107 }
2108 } else {
2109 // This is a touch event with possibly multiple touch points.
2110 // Each touch point may have its own target. So iterate through
2111 // all of them and collect the unique set of targets for event
2112 // forwarding.
2113 //
2114 // This loop is similar to the one used in
2115 // PresShell::DispatchTouchEvent().
2116 const WidgetTouchEvent::TouchArray& touches =
2117 aEvent->AsTouchEvent()->mTouches;
2118 for (uint32_t i = 0; i < touches.Length(); ++i) {
2119 Touch* touch = touches[i];
2120 // NB: the |mChanged| check is an optimization, subprocesses can
2121 // compute this for themselves. If the touch hasn't changed, we
2122 // may be able to avoid forwarding the event entirely (which is
2123 // not free).
2124 if (!touch || !touch->mChanged) {
2125 continue;
2126 }
2127 nsCOMPtr<EventTarget> targetPtr = touch->mTarget;
2128 if (!targetPtr) {
2129 continue;
2130 }
2131 nsCOMPtr<nsIContent> target = do_QueryInterface(targetPtr);
2132 BrowserParent* remoteTarget = BrowserParent::GetFrom(target);
2133 if (remoteTarget && !remoteTargets.Contains(remoteTarget)) {
2134 remoteTargets.AppendElement(remoteTarget);
2135 }
2136 }
2137 }
2138
2139 if (remoteTargets.Length() == 0) {
2140 return false;
2141 }
2142
2143 // Dispatch the event to the remote target.
2144 for (uint32_t i = 0; i < remoteTargets.Length(); ++i) {
2145 DispatchCrossProcessEvent(aEvent, remoteTargets[i], aStatus);
2146 }
2147 return aEvent->HasBeenPostedToRemoteProcess();
2148}
2149
2150//
2151// CreateClickHoldTimer
2152//
2153// Fire off a timer for determining if the user wants click-hold. This timer
2154// is a one-shot that will be cancelled when the user moves enough to fire
2155// a drag.
2156//
2157void EventStateManager::CreateClickHoldTimer(nsPresContext* inPresContext,
2158 nsIFrame* inDownFrame,
2159 WidgetGUIEvent* inMouseDownEvent) {
2160 if (!inMouseDownEvent->IsTrusted() ||
2161 IsTopLevelRemoteTarget(mGestureDownContent) ||
2162 PointerLockManager::IsLocked()) {
2163 return;
2164 }
2165
2166 // just to be anal (er, safe)
2167 if (mClickHoldTimer) {
2168 mClickHoldTimer->Cancel();
2169 mClickHoldTimer = nullptr;
2170 }
2171
2172 // if content clicked on has a popup, don't even start the timer
2173 // since we'll end up conflicting and both will show.
2174 if (mGestureDownContent &&
2175 nsContentUtils::HasNonEmptyAttr(mGestureDownContent, kNameSpaceID_None,
2176 nsGkAtoms::popup)) {
2177 return;
2178 }
2179
2180 int32_t clickHoldDelay = StaticPrefs::ui_click_hold_context_menus_delay();
2181 NS_NewTimerWithFuncCallback(
2182 getter_AddRefs(mClickHoldTimer), sClickHoldCallback, this, clickHoldDelay,
2183 nsITimer::TYPE_ONE_SHOT, "EventStateManager::CreateClickHoldTimer");
2184} // CreateClickHoldTimer
2185
2186//
2187// KillClickHoldTimer
2188//
2189// Stop the timer that would show the context menu dead in its tracks
2190//
2191void EventStateManager::KillClickHoldTimer() {
2192 if (mClickHoldTimer) {
2193 mClickHoldTimer->Cancel();
2194 mClickHoldTimer = nullptr;
2195 }
2196}
2197
2198//
2199// sClickHoldCallback
2200//
2201// This fires after the mouse has been down for a certain length of time.
2202//
2203void EventStateManager::sClickHoldCallback(nsITimer* aTimer, void* aESM) {
2204 RefPtr<EventStateManager> self = static_cast<EventStateManager*>(aESM);
2205 if (self) {
2206 self->FireContextClick();
2207 }
2208
2209 // NOTE: |aTimer| and |self->mAutoHideTimer| are invalid after calling
2210 // ClosePopup();
2211
2212} // sAutoHideCallback
2213
2214//
2215// FireContextClick
2216//
2217// If we're this far, our timer has fired, which means the mouse has been down
2218// for a certain period of time and has not moved enough to generate a
2219// dragGesture. We can be certain the user wants a context-click at this stage,
2220// so generate a dom event and fire it in.
2221//
2222// After the event fires, check if PreventDefault() has been set on the event
2223// which means that someone either ate the event or put up a context menu. This
2224// is our cue to stop tracking the drag gesture. If we always did this,
2225// draggable items w/out a context menu wouldn't be draggable after a certain
2226// length of time, which is _not_ what we want.
2227//
2228void EventStateManager::FireContextClick() {
2229 if (!mGestureDownContent || !mPresContext || PointerLockManager::IsLocked()) {
2230 return;
2231 }
2232
2233#ifdef XP_MACOSX
2234 // Hack to ensure that we don't show a context menu when the user
2235 // let go of the mouse after a long cpu-hogging operation prevented
2236 // us from handling any OS events. See bug 117589.
2237 if (!CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState,
2238 kCGMouseButtonLeft))
2239 return;
2240#endif
2241
2242 nsEventStatus status = nsEventStatus_eIgnore;
2243
2244 // Dispatch to the DOM. We have to fake out the ESM and tell it that the
2245 // current target frame is actually where the mouseDown occurred, otherwise it
2246 // will use the frame the mouse is currently over which may or may not be
2247 // the same. (Note: saari and I have decided that we don't have to reset
2248 // |mCurrentTarget| when we're through because no one else is doing anything
2249 // more with this event and it will get reset on the very next event to the
2250 // correct frame).
2251 mCurrentTarget = mPresContext->GetPrimaryFrameFor(mGestureDownContent);
2252 // make sure the widget sticks around
2253 nsCOMPtr<nsIWidget> targetWidget;
2254 if (mCurrentTarget && (targetWidget = mCurrentTarget->GetNearestWidget())) {
2255 NS_ASSERTION(do { if (!(mPresContext == mCurrentTarget->PresContext()))
{ NS_DebugBreak(NS_DEBUG_ASSERTION, "a prescontext returned a primary frame that didn't belong to it?"
, "mPresContext == mCurrentTarget->PresContext()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2257); MOZ_PretendNoReturn(); } } while (0)
2256 mPresContext == mCurrentTarget->PresContext(),do { if (!(mPresContext == mCurrentTarget->PresContext()))
{ NS_DebugBreak(NS_DEBUG_ASSERTION, "a prescontext returned a primary frame that didn't belong to it?"
, "mPresContext == mCurrentTarget->PresContext()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2257); MOZ_PretendNoReturn(); } } while (0)
2257 "a prescontext returned a primary frame that didn't belong to it?")do { if (!(mPresContext == mCurrentTarget->PresContext()))
{ NS_DebugBreak(NS_DEBUG_ASSERTION, "a prescontext returned a primary frame that didn't belong to it?"
, "mPresContext == mCurrentTarget->PresContext()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2257); MOZ_PretendNoReturn(); } } while (0)
;
2258
2259 // before dispatching, check that we're not on something that
2260 // doesn't get a context menu
2261 bool allowedToDispatch = true;
2262
2263 if (mGestureDownContent->IsAnyOfXULElements(nsGkAtoms::scrollbar,
2264 nsGkAtoms::scrollbarbutton,
2265 nsGkAtoms::button)) {
2266 allowedToDispatch = false;
2267 } else if (mGestureDownContent->IsXULElement(nsGkAtoms::toolbarbutton)) {
2268 // a <toolbarbutton> that has the container attribute set
2269 // will already have its own dropdown.
2270 if (nsContentUtils::HasNonEmptyAttr(
2271 mGestureDownContent, kNameSpaceID_None, nsGkAtoms::container)) {
2272 allowedToDispatch = false;
2273 } else {
2274 // If the toolbar button has an open menu, don't attempt to open
2275 // a second menu
2276 if (mGestureDownContent->IsElement() &&
2277 mGestureDownContent->AsElement()->AttrValueIs(
2278 kNameSpaceID_None, nsGkAtoms::open, nsGkAtoms::_true,
2279 eCaseMatters)) {
2280 allowedToDispatch = false;
2281 }
2282 }
2283 } else if (mGestureDownContent->IsHTMLElement()) {
2284 if (const auto* formCtrl =
2285 nsIFormControl::FromNode(mGestureDownContent)) {
2286 allowedToDispatch =
2287 formCtrl->IsTextControl(/*aExcludePassword*/ false) ||
2288 formCtrl->ControlType() == FormControlType::InputFile;
2289 } else if (mGestureDownContent->IsAnyOfHTMLElements(
2290 nsGkAtoms::embed, nsGkAtoms::object, nsGkAtoms::label)) {
2291 allowedToDispatch = false;
2292 }
2293 }
2294
2295 if (allowedToDispatch) {
2296 // init the event while mCurrentTarget is still good
2297 Maybe<WidgetPointerEvent> pointerEvent;
2298 Maybe<WidgetMouseEvent> mouseEvent;
2299 if (StaticPrefs::
2300 dom_w3c_pointer_events_dispatch_click_as_pointer_event()) {
2301 pointerEvent.emplace(true, eContextMenu, targetWidget);
2302 } else {
2303 mouseEvent.emplace(true, eContextMenu, targetWidget,
2304 WidgetMouseEvent::eReal);
2305 }
2306 WidgetMouseEvent& event =
2307 pointerEvent.isSome() ? pointerEvent.ref() : mouseEvent.ref();
2308 event.mClickCount = 1;
2309 FillInEventFromGestureDown(&event);
2310
2311 // we need to forget the clicking content and click count for the
2312 // following eMouseUp event when click-holding context menus
2313 LastMouseDownInfo& mouseDownInfo = GetLastMouseDownInfo(event.mButton);
2314 mouseDownInfo.mLastMouseDownContent = nullptr;
2315 mouseDownInfo.mClickCount = 0;
2316 mouseDownInfo.mLastMouseDownInputControlType = Nothing();
2317
2318 // stop selection tracking, we're in control now
2319 if (mCurrentTarget) {
2320 RefPtr<nsFrameSelection> frameSel = mCurrentTarget->GetFrameSelection();
2321
2322 if (frameSel && frameSel->GetDragState()) {
2323 // note that this can cause selection changed events to fire if we're
2324 // in a text field, which will null out mCurrentTarget
2325 frameSel->SetDragState(false);
2326 }
2327 }
2328
2329 AutoHandlingUserInputStatePusher userInpStatePusher(true, &event);
2330
2331 // dispatch to DOM
2332 RefPtr<nsPresContext> presContext = mPresContext;
2333
2334 // The contextmenu event handled by PresShell will apply to elements (not
2335 // all nodes) correctly and will be dispatched to EventStateManager for
2336 // further handling preventing click event and stopping tracking drag
2337 // gesture.
2338 if (RefPtr<PresShell> presShell = presContext->GetPresShell()) {
2339 presShell->HandleEvent(mCurrentTarget, &event, false, &status);
2340 }
2341
2342 // We don't need to dispatch to frame handling because no frames
2343 // watch eContextMenu except for nsMenuFrame and that's only for
2344 // dismissal. That's just as well since we don't really know
2345 // which frame to send it to.
2346 }
2347 }
2348
2349 // stop tracking a drag whatever the event has been handled or not.
2350 StopTrackingDragGesture(true);
2351
2352 KillClickHoldTimer();
2353
2354} // FireContextClick
2355
2356//
2357// BeginTrackingDragGesture
2358//
2359// Record that the mouse has gone down and that we should move to TRACKING state
2360// of d&d gesture tracker.
2361//
2362// We also use this to track click-hold context menus. When the mouse goes down,
2363// fire off a short timer. If the timer goes off and we have yet to fire the
2364// drag gesture (ie, the mouse hasn't moved a certain distance), then we can
2365// assume the user wants a click-hold, so fire a context-click event. We only
2366// want to cancel the drag gesture if the context-click event is handled.
2367//
2368void EventStateManager::BeginTrackingDragGesture(nsPresContext* aPresContext,
2369 WidgetMouseEvent* inDownEvent,
2370 nsIFrame* inDownFrame) {
2371 if (!inDownEvent->mWidget) {
2372 return;
2373 }
2374
2375 // Note that |inDownEvent| could be either a mouse down event or a
2376 // synthesized mouse move event.
2377 SetGestureDownPoint(inDownEvent);
2378
2379 if (inDownFrame) {
2380 inDownFrame->GetContentForEvent(inDownEvent,
2381 getter_AddRefs(mGestureDownContent));
2382
2383 mGestureDownFrameOwner = inDownFrame->GetContent();
2384 if (!mGestureDownFrameOwner) {
2385 mGestureDownFrameOwner = mGestureDownContent;
2386 }
2387 }
2388 mGestureModifiers = inDownEvent->mModifiers;
2389 mGestureDownButtons = inDownEvent->mButtons;
2390 mGestureDownButton = inDownEvent->mButton;
2391
2392 if (inDownEvent->mMessage != eMouseTouchDrag &&
2393 StaticPrefs::ui_click_hold_context_menus()) {
2394 // fire off a timer to track click-hold
2395 CreateClickHoldTimer(aPresContext, inDownFrame, inDownEvent);
2396 }
2397}
2398
2399void EventStateManager::SetGestureDownPoint(WidgetGUIEvent* aEvent) {
2400 mGestureDownPoint =
2401 GetEventRefPoint(aEvent) + aEvent->mWidget->WidgetToScreenOffset();
2402}
2403
2404LayoutDeviceIntPoint EventStateManager::GetEventRefPoint(
2405 WidgetEvent* aEvent) const {
2406 auto touchEvent = aEvent->AsTouchEvent();
2407 return (touchEvent && !touchEvent->mTouches.IsEmpty())
2408 ? aEvent->AsTouchEvent()->mTouches[0]->mRefPoint
2409 : aEvent->mRefPoint;
2410}
2411
2412void EventStateManager::BeginTrackingRemoteDragGesture(
2413 nsIContent* aContent, RemoteDragStartData* aDragStartData) {
2414 mGestureDownContent = aContent;
2415 mGestureDownFrameOwner = aContent;
2416 mGestureDownInTextControl =
2417 aContent && aContent->IsInNativeAnonymousSubtree() &&
2418 TextControlElement::FromNodeOrNull(
2419 aContent->GetClosestNativeAnonymousSubtreeRootParentOrHost());
2420 mGestureDownDragStartData = aDragStartData;
2421}
2422
2423//
2424// StopTrackingDragGesture
2425//
2426// Record that the mouse has gone back up so that we should leave the TRACKING
2427// state of d&d gesture tracker and return to the START state.
2428//
2429void EventStateManager::StopTrackingDragGesture(bool aClearInChildProcesses) {
2430 mGestureDownContent = nullptr;
2431 mGestureDownFrameOwner = nullptr;
2432 mGestureDownInTextControl = false;
2433 mGestureDownDragStartData = nullptr;
2434
2435 // If a content process starts a drag but the mouse is released before the
2436 // parent starts the actual drag, the content process will think a drag is
2437 // still happening. Inform any child processes with active drags that the drag
2438 // should be stopped.
2439 if (aClearInChildProcesses) {
2440 nsCOMPtr<nsIDragService> dragService =
2441 do_GetService("@mozilla.org/widget/dragservice;1");
2442 if (dragService) {
2443 RefPtr<nsIDragSession> dragSession =
2444 dragService->GetCurrentSession(mPresContext->GetRootWidget());
2445 if (!dragSession) {
2446 // Only notify if there isn't a drag session active.
2447 dragService->RemoveAllBrowsers();
2448 }
2449 }
2450 }
2451}
2452
2453void EventStateManager::FillInEventFromGestureDown(WidgetMouseEvent* aEvent) {
2454 NS_ASSERTION(aEvent->mWidget == mCurrentTarget->GetNearestWidget(),do { if (!(aEvent->mWidget == mCurrentTarget->GetNearestWidget
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Incorrect widget in event"
, "aEvent->mWidget == mCurrentTarget->GetNearestWidget()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2455); MOZ_PretendNoReturn(); } } while (0)
2455 "Incorrect widget in event")do { if (!(aEvent->mWidget == mCurrentTarget->GetNearestWidget
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Incorrect widget in event"
, "aEvent->mWidget == mCurrentTarget->GetNearestWidget()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2455); MOZ_PretendNoReturn(); } } while (0)
;
2456
2457 // Set the coordinates in the new event to the coordinates of
2458 // the old event, adjusted for the fact that the widget might be
2459 // different
2460 aEvent->mRefPoint =
2461 mGestureDownPoint - aEvent->mWidget->WidgetToScreenOffset();
2462 aEvent->mModifiers = mGestureModifiers;
2463 aEvent->mButtons = mGestureDownButtons;
2464 if (aEvent->mMessage == eContextMenu) {
2465 aEvent->mButton = mGestureDownButton;
2466 }
2467}
2468
2469void EventStateManager::MaybeFirePointerCancel(WidgetInputEvent* aEvent) {
2470 RefPtr<PresShell> presShell = mPresContext->GetPresShell();
2471 AutoWeakFrame targetFrame = mCurrentTarget;
2472
2473 if (!presShell || !targetFrame) {
2474 return;
2475 }
2476
2477 nsCOMPtr<nsIContent> content;
2478 targetFrame->GetContentForEvent(aEvent, getter_AddRefs(content));
2479 if (!content) {
2480 return;
2481 }
2482
2483 nsEventStatus status = nsEventStatus_eIgnore;
2484
2485 if (WidgetMouseEvent* aMouseEvent = aEvent->AsMouseEvent()) {
2486 WidgetPointerEvent event(*aMouseEvent);
2487 PointerEventHandler::InitPointerEventFromMouse(&event, aMouseEvent,
2488 ePointerCancel);
2489
2490 event.convertToPointer = false;
2491 presShell->HandleEventWithTarget(&event, targetFrame, content, &status);
2492 } else if (WidgetTouchEvent* aTouchEvent = aEvent->AsTouchEvent()) {
2493 WidgetPointerEvent event(aTouchEvent->IsTrusted(), ePointerCancel,
2494 aTouchEvent->mWidget);
2495
2496 PointerEventHandler::InitPointerEventFromTouch(event, *aTouchEvent,
2497 *aTouchEvent->mTouches[0]);
2498
2499 event.convertToPointer = false;
2500 presShell->HandleEventWithTarget(&event, targetFrame, content, &status);
2501 } else {
2502 MOZ_ASSERT(false)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2502); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ")")
; do { *((volatile int*)__null) = 2502; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2503 }
2504
2505 // HandleEventWithTarget clears out mCurrentTarget, which may be used in the
2506 // caller GenerateDragGesture. We have to restore mCurrentTarget.
2507 mCurrentTarget = targetFrame;
2508}
2509
2510bool EventStateManager::IsEventOutsideDragThreshold(
2511 WidgetInputEvent* aEvent) const {
2512 static int32_t sPixelThresholdX = 0;
2513 static int32_t sPixelThresholdY = 0;
2514
2515 if (!sPixelThresholdX) {
2516 sPixelThresholdX =
2517 LookAndFeel::GetInt(LookAndFeel::IntID::DragThresholdX, 0);
2518 sPixelThresholdY =
2519 LookAndFeel::GetInt(LookAndFeel::IntID::DragThresholdY, 0);
2520 if (sPixelThresholdX <= 0) {
2521 sPixelThresholdX = 5;
2522 }
2523 if (sPixelThresholdY <= 0) {
2524 sPixelThresholdY = 5;
2525 }
2526 }
2527
2528 LayoutDeviceIntPoint pt =
2529 aEvent->mWidget->WidgetToScreenOffset() + GetEventRefPoint(aEvent);
2530 LayoutDeviceIntPoint distance = pt - mGestureDownPoint;
2531 return Abs(distance.x) > sPixelThresholdX ||
2532 Abs(distance.y) > sPixelThresholdY;
2533}
2534
2535//
2536// GenerateDragGesture
2537//
2538// If we're in the TRACKING state of the d&d gesture tracker, check the current
2539// position of the mouse in relation to the old one. If we've moved a sufficient
2540// amount from the mouse down, then fire off a drag gesture event.
2541void EventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
2542 WidgetInputEvent* aEvent) {
2543 NS_ASSERTION(aPresContext, "This shouldn't happen.")do { if (!(aPresContext)) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"This shouldn't happen.", "aPresContext", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2543); MOZ_PretendNoReturn(); } } while (0)
;
2544 if (!IsTrackingDragGesture()) {
2545 return;
2546 }
2547
2548 AutoWeakFrame targetFrameBefore = mCurrentTarget;
2549 auto autoRestore = MakeScopeExit([&] { mCurrentTarget = targetFrameBefore; });
2550 mCurrentTarget = mGestureDownFrameOwner->GetPrimaryFrame();
2551
2552 if (!mCurrentTarget || !mCurrentTarget->GetNearestWidget()) {
2553 StopTrackingDragGesture(true);
2554 return;
2555 }
2556
2557 // Check if selection is tracking drag gestures, if so
2558 // don't interfere!
2559 if (mCurrentTarget) {
2560 RefPtr<nsFrameSelection> frameSel = mCurrentTarget->GetFrameSelection();
2561 if (frameSel && frameSel->GetDragState()) {
2562 StopTrackingDragGesture(true);
2563 return;
2564 }
2565 }
2566
2567 // If non-native code is capturing the mouse don't start a drag.
2568 if (PresShell::IsMouseCapturePreventingDrag()) {
2569 StopTrackingDragGesture(true);
2570 return;
2571 }
2572
2573 if (!IsEventOutsideDragThreshold(aEvent)) {
2574 // To keep the old behavior, flush layout even if we don't start dnd.
2575 FlushLayout(aPresContext);
2576 return;
2577 }
2578
2579 if (StaticPrefs::ui_click_hold_context_menus()) {
2580 // stop the click-hold before we fire off the drag gesture, in case
2581 // it takes a long time
2582 KillClickHoldTimer();
2583 }
2584
2585 nsCOMPtr<nsIDocShell> docshell = aPresContext->GetDocShell();
2586 if (!docshell) {
2587 return;
2588 }
2589
2590 nsCOMPtr<nsPIDOMWindowOuter> window = docshell->GetWindow();
2591 if (!window) return;
2592
2593 RefPtr<DataTransfer> dataTransfer =
2594 new DataTransfer(window, eDragStart, /* aIsExternal */ false,
2595 /* aClipboardType */ Nothing());
2596 auto protectDataTransfer = MakeScopeExit([&] {
2597 if (dataTransfer) {
2598 dataTransfer->Disconnect();
2599 }
2600 });
2601
2602 RefPtr<Selection> selection;
2603 RefPtr<RemoteDragStartData> remoteDragStartData;
2604 nsCOMPtr<nsIContent> eventContent, targetContent;
2605 nsCOMPtr<nsIPrincipal> principal;
2606 nsCOMPtr<nsIContentSecurityPolicy> csp;
2607 nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
2608 bool allowEmptyDataTransfer = false;
2609 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(eventContent));
2610 if (eventContent) {
2611 // If the content is a text node in a password field, we shouldn't
2612 // allow to drag its raw text. Note that we've supported drag from
2613 // password fields but dragging data was masked text. So, it doesn't
2614 // make sense anyway.
2615 if (eventContent->IsText() && eventContent->HasFlag(NS_MAYBE_MASKED)) {
2616 // However, it makes sense to allow to drag selected password text
2617 // when copying selected password is allowed because users may want
2618 // to use drag and drop rather than copy and paste when web apps
2619 // request to input password twice for conforming new password but
2620 // they used password generator.
2621 TextEditor* textEditor =
2622 nsContentUtils::GetTextEditorFromAnonymousNodeWithoutCreation(
2623 eventContent);
2624 if (!textEditor || !textEditor->IsCopyToClipboardAllowed()) {
2625 StopTrackingDragGesture(true);
2626 return;
2627 }
2628 }
2629 DetermineDragTargetAndDefaultData(
2630 window, eventContent, dataTransfer, &allowEmptyDataTransfer,
2631 getter_AddRefs(selection), getter_AddRefs(remoteDragStartData),
2632 getter_AddRefs(targetContent), getter_AddRefs(principal),
2633 getter_AddRefs(csp), getter_AddRefs(cookieJarSettings));
2634 }
2635
2636 // Stop tracking the drag gesture now. This should stop us from
2637 // reentering GenerateDragGesture inside DOM event processing.
2638 // Pass false to avoid clearing the child process state since a real
2639 // drag should be starting.
2640 StopTrackingDragGesture(false);
2641
2642 if (!targetContent) return;
2643
2644 // Use our targetContent, now that we've determined it, as the
2645 // parent object of the DataTransfer.
2646 nsCOMPtr<nsIContent> parentContent =
2647 targetContent->FindFirstNonChromeOnlyAccessContent();
2648 dataTransfer->SetParentObject(parentContent);
2649
2650 sLastDragOverFrame = nullptr;
2651 nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget();
2652
2653 // get the widget from the target frame
2654 WidgetDragEvent startEvent(aEvent->IsTrusted(), eDragStart, widget);
2655 startEvent.mFlags.mIsSynthesizedForTests =
2656 aEvent->mFlags.mIsSynthesizedForTests;
2657 FillInEventFromGestureDown(&startEvent);
2658
2659 startEvent.mDataTransfer = dataTransfer;
2660 if (aEvent->AsMouseEvent()) {
2661 startEvent.mInputSource = aEvent->AsMouseEvent()->mInputSource;
2662 } else if (aEvent->AsTouchEvent()) {
2663 startEvent.mInputSource = MouseEvent_Binding::MOZ_SOURCE_TOUCH;
2664 } else {
2665 MOZ_ASSERT(false)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2665); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ")")
; do { *((volatile int*)__null) = 2665; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2666 }
2667
2668 // Dispatch to the DOM. By setting mCurrentTarget we are faking
2669 // out the ESM and telling it that the current target frame is
2670 // actually where the mouseDown occurred, otherwise it will use
2671 // the frame the mouse is currently over which may or may not be
2672 // the same.
2673
2674 // Hold onto old target content through the event and reset after.
2675 nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
2676
2677 // Set the current target to the content for the mouse down
2678 mCurrentTargetContent = targetContent;
2679
2680 // Dispatch the dragstart event to the DOM.
2681 nsEventStatus status = nsEventStatus_eIgnore;
2682 EventDispatcher::Dispatch(targetContent, aPresContext, &startEvent, nullptr,
2683 &status);
2684
2685 WidgetDragEvent* event = &startEvent;
2686
2687 nsCOMPtr<nsIObserverService> observerService =
2688 mozilla::services::GetObserverService();
2689 // Emit observer event to allow addons to modify the DataTransfer
2690 // object.
2691 if (observerService) {
2692 observerService->NotifyObservers(dataTransfer, "on-datatransfer-available",
2693 nullptr);
2694 }
2695
2696 if (status != nsEventStatus_eConsumeNoDefault) {
2697 bool dragStarted = DoDefaultDragStart(aPresContext, event, dataTransfer,
2698 allowEmptyDataTransfer, targetContent,
2699 selection, remoteDragStartData,
2700 principal, csp, cookieJarSettings);
2701 if (dragStarted) {
2702 sActiveESM = nullptr;
2703 MaybeFirePointerCancel(aEvent);
2704 aEvent->StopPropagation();
2705 }
2706 }
2707
2708 // Reset mCurretTargetContent to what it was
2709 mCurrentTargetContent = targetBeforeEvent;
2710
2711 // Now flush all pending notifications, for better responsiveness
2712 // while dragging.
2713 FlushLayout(aPresContext);
2714} // GenerateDragGesture
2715
2716void EventStateManager::DetermineDragTargetAndDefaultData(
2717 nsPIDOMWindowOuter* aWindow, nsIContent* aSelectionTarget,
2718 DataTransfer* aDataTransfer, bool* aAllowEmptyDataTransfer,
2719 Selection** aSelection, RemoteDragStartData** aRemoteDragStartData,
2720 nsIContent** aTargetNode, nsIPrincipal** aPrincipal,
2721 nsIContentSecurityPolicy** aCsp,
2722 nsICookieJarSettings** aCookieJarSettings) {
2723 *aTargetNode = nullptr;
2724 *aAllowEmptyDataTransfer = false;
2725 nsCOMPtr<nsIContent> dragDataNode;
2726
2727 nsIContent* editingElement = aSelectionTarget->IsEditable()
2728 ? aSelectionTarget->GetEditingHost()
2729 : nullptr;
2730
2731 // In chrome, only allow dragging inside editable areas.
2732 bool isChromeContext = !aWindow->GetBrowsingContext()->IsContent();
2733 if (isChromeContext && !editingElement) {
2734 if (mGestureDownDragStartData) {
2735 // A child process started a drag so use any data it assigned for the dnd
2736 // session.
2737 mGestureDownDragStartData->AddInitialDnDDataTo(aDataTransfer, aPrincipal,
2738 aCsp, aCookieJarSettings);
2739 mGestureDownDragStartData.forget(aRemoteDragStartData);
2740 *aAllowEmptyDataTransfer = true;
2741 }
2742 } else {
2743 mGestureDownDragStartData = nullptr;
2744
2745 // GetDragData determines if a selection, link or image in the content
2746 // should be dragged, and places the data associated with the drag in the
2747 // data transfer.
2748 // mGestureDownContent is the node where the mousedown event for the drag
2749 // occurred, and aSelectionTarget is the node to use when a selection is
2750 // used
2751 bool canDrag;
2752 bool wasAlt = (mGestureModifiers & MODIFIER_ALT) != 0;
2753 nsresult rv = nsContentAreaDragDrop::GetDragData(
2754 aWindow, mGestureDownContent, aSelectionTarget, wasAlt, aDataTransfer,
2755 &canDrag, aSelection, getter_AddRefs(dragDataNode), aCsp,
2756 aCookieJarSettings);
2757 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !canDrag) {
2758 return;
2759 }
2760 }
2761
2762 // if GetDragData returned a node, use that as the node being dragged.
2763 // Otherwise, if a selection is being dragged, use the node within the
2764 // selection that was dragged. Otherwise, just use the mousedown target.
2765 nsIContent* dragContent = mGestureDownContent;
2766 if (dragDataNode)
2767 dragContent = dragDataNode;
2768 else if (*aSelection)
2769 dragContent = aSelectionTarget;
2770
2771 nsIContent* originalDragContent = dragContent;
2772
2773 // If a selection isn't being dragged, look for an ancestor with the
2774 // draggable property set. If one is found, use that as the target of the
2775 // drag instead of the node that was clicked on. If a draggable node wasn't
2776 // found, just use the clicked node.
2777 if (!*aSelection) {
2778 while (dragContent) {
2779 if (auto htmlElement = nsGenericHTMLElement::FromNode(dragContent)) {
2780 if (htmlElement->Draggable()) {
2781 // We let draggable elements to trigger dnd even if there is no data
2782 // in the DataTransfer.
2783 *aAllowEmptyDataTransfer = true;
2784 break;
2785 }
2786 } else {
2787 if (dragContent->IsXULElement()) {
2788 // All XUL elements are draggable, so if a XUL element is
2789 // encountered, stop looking for draggable nodes and just use the
2790 // original clicked node instead.
2791 // XXXndeakin
2792 // In the future, we will want to improve this so that XUL has a
2793 // better way to specify whether something is draggable than just
2794 // on/off.
2795 dragContent = mGestureDownContent;
2796 break;
2797 }
2798 // otherwise, it's not an HTML or XUL element, so just keep looking
2799 }
2800 dragContent = dragContent->GetFlattenedTreeParent();
2801 }
2802 }
2803
2804 // if no node in the hierarchy was found to drag, but the GetDragData method
2805 // returned a node, use that returned node. Otherwise, nothing is draggable.
2806 if (!dragContent && dragDataNode) dragContent = dragDataNode;
2807
2808 if (dragContent) {
2809 // if an ancestor node was used instead, clear the drag data
2810 // XXXndeakin rework this a bit. Find a way to just not call GetDragData if
2811 // we don't need to.
2812 if (dragContent != originalDragContent) aDataTransfer->ClearAll();
2813 *aTargetNode = dragContent;
2814 NS_ADDREF(*aTargetNode)(*aTargetNode)->AddRef();
2815 }
2816}
2817
2818bool EventStateManager::DoDefaultDragStart(
2819 nsPresContext* aPresContext, WidgetDragEvent* aDragEvent,
2820 DataTransfer* aDataTransfer, bool aAllowEmptyDataTransfer,
2821 nsIContent* aDragTarget, Selection* aSelection,
2822 RemoteDragStartData* aDragStartData, nsIPrincipal* aPrincipal,
2823 nsIContentSecurityPolicy* aCsp, nsICookieJarSettings* aCookieJarSettings) {
2824 nsCOMPtr<nsIDragService> dragService =
2825 do_GetService("@mozilla.org/widget/dragservice;1");
2826 if (!dragService) return false;
2827
2828 // Default handling for the dragstart event.
2829 //
2830 // First, check if a drag session already exists. This means that the drag
2831 // service was called directly within a draggesture handler. In this case,
2832 // don't do anything more, as it is assumed that the handler is managing
2833 // drag and drop manually. Make sure to return true to indicate that a drag
2834 // began. However, if we're handling drag session for synthesized events,
2835 // we need to initialize some information of the session. Therefore, we
2836 // need to keep going for synthesized case.
2837 if (MOZ_UNLIKELY(!mPresContext)(__builtin_expect(!!(!mPresContext), 0))) {
2838 return true;
2839 }
2840 nsCOMPtr<nsIDragSession> dragSession =
2841 dragService->GetCurrentSession(mPresContext->GetRootWidget());
2842 if (dragSession && !dragSession->IsSynthesizedForTests()) {
2843 return true;
2844 }
2845
2846 // No drag session is currently active, so check if a handler added
2847 // any items to be dragged. If not, there isn't anything to drag.
2848 uint32_t count = 0;
2849 if (aDataTransfer) {
2850 count = aDataTransfer->MozItemCount();
2851 }
2852 if (!aAllowEmptyDataTransfer && !count) {
2853 return false;
2854 }
2855
2856 // Get the target being dragged, which may not be the same as the
2857 // target of the mouse event. If one wasn't set in the
2858 // aDataTransfer during the event handler, just use the original
2859 // target instead.
2860 nsCOMPtr<nsIContent> dragTarget = aDataTransfer->GetDragTarget();
2861 if (!dragTarget) {
2862 dragTarget = aDragTarget;
2863 if (!dragTarget) {
2864 return false;
2865 }
2866 }
2867
2868 // check which drag effect should initially be used. If the effect was not
2869 // set, just use all actions, otherwise Windows won't allow a drop.
2870 uint32_t action = aDataTransfer->EffectAllowedInt();
2871 if (action == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED) {
2872 action = nsIDragService::DRAGDROP_ACTION_COPY |
2873 nsIDragService::DRAGDROP_ACTION_MOVE |
2874 nsIDragService::DRAGDROP_ACTION_LINK;
2875 }
2876
2877 // get any custom drag image that was set
2878 int32_t imageX, imageY;
2879 RefPtr<Element> dragImage = aDataTransfer->GetDragImage(&imageX, &imageY);
2880
2881 nsCOMPtr<nsIArray> transArray = aDataTransfer->GetTransferables(dragTarget);
2882 if (!transArray) {
2883 return false;
2884 }
2885
2886 RefPtr<DataTransfer> dataTransfer;
2887 if (!dragSession) {
2888 // After this function returns, the DataTransfer will be cleared so it
2889 // appears empty to content. We need to pass a DataTransfer into the Drag
2890 // Session, so we need to make a copy.
2891 aDataTransfer->Clone(aDragTarget, eDrop, aDataTransfer->MozUserCancelled(),
2892 false, getter_AddRefs(dataTransfer));
2893
2894 // Copy over the drop effect, as Clone doesn't copy it for us.
2895 dataTransfer->SetDropEffectInt(aDataTransfer->DropEffectInt());
2896 } else {
2897 MOZ_ASSERT(dragSession->IsSynthesizedForTests())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(dragSession->IsSynthesizedForTests())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(dragSession->IsSynthesizedForTests()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("dragSession->IsSynthesizedForTests()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2897); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dragSession->IsSynthesizedForTests()"
")"); do { *((volatile int*)__null) = 2897; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2898 MOZ_ASSERT(aDragEvent->mFlags.mIsSynthesizedForTests)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDragEvent->mFlags.mIsSynthesizedForTests)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aDragEvent->mFlags.mIsSynthesizedForTests))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aDragEvent->mFlags.mIsSynthesizedForTests"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2898); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDragEvent->mFlags.mIsSynthesizedForTests"
")"); do { *((volatile int*)__null) = 2898; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2899 // If we're initializing synthesized drag session, we should use given
2900 // DataTransfer as is because it'll be used with following drag events
2901 // in any tests, therefore it should be set to nsIDragSession.dataTransfer
2902 // because it and DragEvent.dataTransfer should be same instance.
2903 dataTransfer = aDataTransfer;
2904 }
2905
2906 // XXXndeakin don't really want to create a new drag DOM event
2907 // here, but we need something to pass to the InvokeDragSession
2908 // methods.
2909 RefPtr<DragEvent> event =
2910 NS_NewDOMDragEvent(dragTarget, aPresContext, aDragEvent);
2911
2912 // Use InvokeDragSessionWithSelection if a selection is being dragged,
2913 // such that the image can be generated from the selected text. However,
2914 // use InvokeDragSessionWithImage if a custom image was set or something
2915 // other than a selection is being dragged.
2916 if (!dragImage && aSelection) {
2917 dragService->InvokeDragSessionWithSelection(
2918 aSelection, aPrincipal, aCsp, aCookieJarSettings, transArray, action,
2919 event, dataTransfer, dragTarget);
2920 } else if (aDragStartData) {
2921 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2921); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 2921; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2922 dragService->InvokeDragSessionWithRemoteImage(
2923 dragTarget, aPrincipal, aCsp, aCookieJarSettings, transArray, action,
2924 aDragStartData, event, dataTransfer);
2925 } else {
2926 dragService->InvokeDragSessionWithImage(
2927 dragTarget, aPrincipal, aCsp, aCookieJarSettings, transArray, action,
2928 dragImage, imageX, imageY, event, dataTransfer);
2929 }
2930
2931 return true;
2932}
2933
2934void EventStateManager::ChangeZoom(bool aIncrease) {
2935 // Send the zoom change to the top level browser so it will be handled by the
2936 // front end in the same way as other zoom actions.
2937 nsIDocShell* docShell = mDocument->GetDocShell();
2938 if (!docShell) {
2939 return;
2940 }
2941
2942 BrowsingContext* bc = docShell->GetBrowsingContext();
2943 if (!bc) {
2944 return;
2945 }
2946
2947 if (XRE_IsParentProcess()) {
2948 bc->Canonical()->DispatchWheelZoomChange(aIncrease);
2949 } else if (BrowserChild* child = BrowserChild::GetFrom(docShell)) {
2950 child->SendWheelZoomChange(aIncrease);
2951 }
2952}
2953
2954void EventStateManager::DoScrollHistory(int32_t direction) {
2955 nsCOMPtr<nsISupports> pcContainer(mPresContext->GetContainerWeak());
2956 if (pcContainer) {
2957 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(pcContainer));
2958 if (webNav) {
2959 // positive direction to go back one step, nonpositive to go forward
2960 // This is doing user-initiated history traversal, hence we want
2961 // to require that history entries we navigate to have user interaction.
2962 if (direction > 0)
2963 webNav->GoBack(StaticPrefs::browser_navigation_requireUserInteraction(),
2964 true);
2965 else
2966 webNav->GoForward(
2967 StaticPrefs::browser_navigation_requireUserInteraction(), true);
2968 }
2969 }
2970}
2971
2972void EventStateManager::DoScrollZoom(nsIFrame* aTargetFrame,
2973 int32_t adjustment) {
2974 // Exclude content in chrome docshells.
2975 nsIContent* content = aTargetFrame->GetContent();
2976 if (content && !nsContentUtils::IsInChromeDocshell(content->OwnerDoc())) {
2977 // Positive adjustment to decrease zoom, negative to increase
2978 const bool increase = adjustment <= 0;
2979 EnsureDocument(mPresContext);
2980 ChangeZoom(increase);
2981 }
2982}
2983
2984static nsIFrame* GetParentFrameToScroll(nsIFrame* aFrame) {
2985 if (!aFrame) return nullptr;
2986
2987 if (aFrame->StyleDisplay()->mPosition == StylePositionProperty::Fixed &&
2988 nsLayoutUtils::IsReallyFixedPos(aFrame)) {
2989 return aFrame->PresShell()->GetRootScrollContainerFrame();
2990 }
2991 return aFrame->GetParent();
2992}
2993
2994void EventStateManager::DispatchLegacyMouseScrollEvents(
2995 nsIFrame* aTargetFrame, WidgetWheelEvent* aEvent, nsEventStatus* aStatus) {
2996 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2996); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 2996; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2997 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2997); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 2997; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2998
2999 if (!aTargetFrame || *aStatus == nsEventStatus_eConsumeNoDefault) {
3000 return;
3001 }
3002
3003 // Ignore mouse wheel transaction for computing legacy mouse wheel
3004 // events' delta value.
3005 // DOM event's delta vales are computed from CSS pixels.
3006 auto scrollAmountInCSSPixels =
3007 CSSIntSize::FromAppUnitsRounded(aEvent->mScrollAmount);
3008
3009 // XXX We don't deal with fractional amount in legacy event, though the
3010 // default action handler (DoScrollText()) deals with it.
3011 // If we implemented such strict computation, we would need additional
3012 // accumulated delta values. It would made the code more complicated.
3013 // And also it would computes different delta values from older version.
3014 // It doesn't make sense to implement such code for legacy events and
3015 // rare cases.
3016 int32_t scrollDeltaX, scrollDeltaY, pixelDeltaX, pixelDeltaY;
3017 switch (aEvent->mDeltaMode) {
3018 case WheelEvent_Binding::DOM_DELTA_PAGE:
3019 scrollDeltaX = !aEvent->mLineOrPageDeltaX
3020 ? 0
3021 : (aEvent->mLineOrPageDeltaX > 0
3022 ? UIEvent_Binding::SCROLL_PAGE_DOWN
3023 : UIEvent_Binding::SCROLL_PAGE_UP);
3024 scrollDeltaY = !aEvent->mLineOrPageDeltaY
3025 ? 0
3026 : (aEvent->mLineOrPageDeltaY > 0
3027 ? UIEvent_Binding::SCROLL_PAGE_DOWN
3028 : UIEvent_Binding::SCROLL_PAGE_UP);
3029 pixelDeltaX = RoundDown(aEvent->mDeltaX * scrollAmountInCSSPixels.width);
3030 pixelDeltaY = RoundDown(aEvent->mDeltaY * scrollAmountInCSSPixels.height);
3031 break;
3032
3033 case WheelEvent_Binding::DOM_DELTA_LINE:
3034 scrollDeltaX = aEvent->mLineOrPageDeltaX;
3035 scrollDeltaY = aEvent->mLineOrPageDeltaY;
3036 pixelDeltaX = RoundDown(aEvent->mDeltaX * scrollAmountInCSSPixels.width);
3037 pixelDeltaY = RoundDown(aEvent->mDeltaY * scrollAmountInCSSPixels.height);
3038 break;
3039
3040 case WheelEvent_Binding::DOM_DELTA_PIXEL:
3041 scrollDeltaX = aEvent->mLineOrPageDeltaX;
3042 scrollDeltaY = aEvent->mLineOrPageDeltaY;
3043 pixelDeltaX = RoundDown(aEvent->mDeltaX);
3044 pixelDeltaY = RoundDown(aEvent->mDeltaY);
3045 break;
3046
3047 default:
3048 MOZ_CRASH("Invalid deltaMode value comes")do { do { } while (false); MOZ_ReportCrash("" "Invalid deltaMode value comes"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3048); AnnotateMozCrashReason("MOZ_CRASH(" "Invalid deltaMode value comes"
")"); do { *((volatile int*)__null) = 3048; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
3049 }
3050
3051 // Send the legacy events in following order:
3052 // 1. Vertical scroll
3053 // 2. Vertical pixel scroll (even if #1 isn't consumed)
3054 // 3. Horizontal scroll (even if #1 and/or #2 are consumed)
3055 // 4. Horizontal pixel scroll (even if #3 isn't consumed)
3056
3057 AutoWeakFrame targetFrame(aTargetFrame);
3058
3059 MOZ_ASSERT(*aStatus != nsEventStatus_eConsumeNoDefault &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault &&
!aEvent->DefaultPrevented())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aStatus != nsEventStatus_eConsumeNoDefault
&& !aEvent->DefaultPrevented()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
" (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3062); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
") (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")"); do {
*((volatile int*)__null) = 3062; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3060 !aEvent->DefaultPrevented(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault &&
!aEvent->DefaultPrevented())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aStatus != nsEventStatus_eConsumeNoDefault
&& !aEvent->DefaultPrevented()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
" (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3062); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
") (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")"); do {
*((volatile int*)__null) = 3062; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3061 "If you make legacy events dispatched for default prevented wheel "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault &&
!aEvent->DefaultPrevented())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aStatus != nsEventStatus_eConsumeNoDefault
&& !aEvent->DefaultPrevented()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
" (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3062); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
") (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")"); do {
*((volatile int*)__null) = 3062; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3062 "event, you need to initialize stateX and stateY")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault &&
!aEvent->DefaultPrevented())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aStatus != nsEventStatus_eConsumeNoDefault
&& !aEvent->DefaultPrevented()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
" (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3062); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
") (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")"); do {
*((volatile int*)__null) = 3062; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
3063 EventState stateX, stateY;
3064 if (scrollDeltaY) {
3065 SendLineScrollEvent(aTargetFrame, aEvent, stateY, scrollDeltaY,
3066 DELTA_DIRECTION_Y);
3067 if (!targetFrame.IsAlive()) {
3068 *aStatus = nsEventStatus_eConsumeNoDefault;
3069 return;
3070 }
3071 }
3072
3073 if (pixelDeltaY) {
3074 SendPixelScrollEvent(aTargetFrame, aEvent, stateY, pixelDeltaY,
3075 DELTA_DIRECTION_Y);
3076 if (!targetFrame.IsAlive()) {
3077 *aStatus = nsEventStatus_eConsumeNoDefault;
3078 return;
3079 }
3080 }
3081
3082 if (scrollDeltaX) {
3083 SendLineScrollEvent(aTargetFrame, aEvent, stateX, scrollDeltaX,
3084 DELTA_DIRECTION_X);
3085 if (!targetFrame.IsAlive()) {
3086 *aStatus = nsEventStatus_eConsumeNoDefault;
3087 return;
3088 }
3089 }
3090
3091 if (pixelDeltaX) {
3092 SendPixelScrollEvent(aTargetFrame, aEvent, stateX, pixelDeltaX,
3093 DELTA_DIRECTION_X);
3094 if (!targetFrame.IsAlive()) {
3095 *aStatus = nsEventStatus_eConsumeNoDefault;
3096 return;
3097 }
3098 }
3099
3100 if (stateY.mDefaultPrevented) {
3101 *aStatus = nsEventStatus_eConsumeNoDefault;
3102 aEvent->PreventDefault(!stateY.mDefaultPreventedByContent);
3103 }
3104
3105 if (stateX.mDefaultPrevented) {
3106 *aStatus = nsEventStatus_eConsumeNoDefault;
3107 aEvent->PreventDefault(!stateX.mDefaultPreventedByContent);
3108 }
3109}
3110
3111void EventStateManager::SendLineScrollEvent(nsIFrame* aTargetFrame,
3112 WidgetWheelEvent* aEvent,
3113 EventState& aState, int32_t aDelta,
3114 DeltaDirection aDeltaDirection) {
3115 nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
3116 if (!targetContent) {
3117 targetContent = GetFocusedElement();
3118 if (!targetContent) {
3119 return;
3120 }
3121 }
3122
3123 while (targetContent->IsText()) {
3124 targetContent = targetContent->GetFlattenedTreeParent();
3125 }
3126
3127 WidgetMouseScrollEvent event(aEvent->IsTrusted(),
3128 eLegacyMouseLineOrPageScroll, aEvent->mWidget);
3129 event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
3130 event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
3131 event.mRefPoint = aEvent->mRefPoint;
3132 event.mTimeStamp = aEvent->mTimeStamp;
3133 event.mModifiers = aEvent->mModifiers;
3134 event.mButtons = aEvent->mButtons;
3135 event.mIsHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
3136 event.mDelta = aDelta;
3137 event.mInputSource = aEvent->mInputSource;
3138
3139 RefPtr<nsPresContext> presContext = aTargetFrame->PresContext();
3140 nsEventStatus status = nsEventStatus_eIgnore;
3141 EventDispatcher::Dispatch(targetContent, presContext, &event, nullptr,
3142 &status);
3143 aState.mDefaultPrevented =
3144 event.DefaultPrevented() || status == nsEventStatus_eConsumeNoDefault;
3145 aState.mDefaultPreventedByContent = event.DefaultPreventedByContent();
3146}
3147
3148void EventStateManager::SendPixelScrollEvent(nsIFrame* aTargetFrame,
3149 WidgetWheelEvent* aEvent,
3150 EventState& aState,
3151 int32_t aPixelDelta,
3152 DeltaDirection aDeltaDirection) {
3153 nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
3154 if (!targetContent) {
3155 targetContent = GetFocusedElement();
3156 if (!targetContent) {
3157 return;
3158 }
3159 }
3160
3161 while (targetContent->IsText()) {
3162 targetContent = targetContent->GetFlattenedTreeParent();
3163 }
3164
3165 WidgetMouseScrollEvent event(aEvent->IsTrusted(), eLegacyMousePixelScroll,
3166 aEvent->mWidget);
3167 event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
3168 event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
3169 event.mRefPoint = aEvent->mRefPoint;
3170 event.mTimeStamp = aEvent->mTimeStamp;
3171 event.mModifiers = aEvent->mModifiers;
3172 event.mButtons = aEvent->mButtons;
3173 event.mIsHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
3174 event.mDelta = aPixelDelta;
3175 event.mInputSource = aEvent->mInputSource;
3176
3177 RefPtr<nsPresContext> presContext = aTargetFrame->PresContext();
3178 nsEventStatus status = nsEventStatus_eIgnore;
3179 EventDispatcher::Dispatch(targetContent, presContext, &event, nullptr,
3180 &status);
3181 aState.mDefaultPrevented =
3182 event.DefaultPrevented() || status == nsEventStatus_eConsumeNoDefault;
3183 aState.mDefaultPreventedByContent = event.DefaultPreventedByContent();
3184}
3185
3186ScrollContainerFrame*
3187EventStateManager::ComputeScrollTargetAndMayAdjustWheelEvent(
3188 nsIFrame* aTargetFrame, WidgetWheelEvent* aEvent,
3189 ComputeScrollTargetOptions aOptions) {
3190 return ComputeScrollTargetAndMayAdjustWheelEvent(
3191 aTargetFrame, aEvent->mDeltaX, aEvent->mDeltaY, aEvent, aOptions);
3192}
3193
3194// Overload ComputeScrollTargetAndMayAdjustWheelEvent method to allow passing
3195// "test" dx and dy when looking for which scrollbarmediators to activate when
3196// two finger down on trackpad and before any actual motion
3197ScrollContainerFrame*
3198EventStateManager::ComputeScrollTargetAndMayAdjustWheelEvent(
3199 nsIFrame* aTargetFrame, double aDirectionX, double aDirectionY,
3200 WidgetWheelEvent* aEvent, ComputeScrollTargetOptions aOptions) {
3201 bool isAutoDir = false;
3202 bool honoursRoot = false;
3203 if (MAY_BE_ADJUSTED_BY_AUTO_DIR & aOptions) {
3204 // If the scroll is respected as auto-dir, aDirection* should always be
3205 // equivalent to the event's delta vlaues(Currently, there are only one case
3206 // where aDirection*s have different values from the widget wheel event's
3207 // original delta values and the only case isn't auto-dir, see
3208 // ScrollbarsForWheel::TemporarilyActivateAllPossibleScrollTargets).
3209 MOZ_ASSERT(aDirectionX == aEvent->mDeltaX &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDirectionX == aEvent->mDeltaX && aDirectionY
== aEvent->mDeltaY)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDirectionX == aEvent->mDeltaX
&& aDirectionY == aEvent->mDeltaY))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aDirectionX == aEvent->mDeltaX && aDirectionY == aEvent->mDeltaY"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3210); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDirectionX == aEvent->mDeltaX && aDirectionY == aEvent->mDeltaY"
")"); do { *((volatile int*)__null) = 3210; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3210 aDirectionY == aEvent->mDeltaY)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDirectionX == aEvent->mDeltaX && aDirectionY
== aEvent->mDeltaY)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDirectionX == aEvent->mDeltaX
&& aDirectionY == aEvent->mDeltaY))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aDirectionX == aEvent->mDeltaX && aDirectionY == aEvent->mDeltaY"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3210); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDirectionX == aEvent->mDeltaX && aDirectionY == aEvent->mDeltaY"
")"); do { *((volatile int*)__null) = 3210; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3211
3212 WheelDeltaAdjustmentStrategy strategy =
3213 GetWheelDeltaAdjustmentStrategy(*aEvent);
3214 switch (strategy) {
3215 case WheelDeltaAdjustmentStrategy::eAutoDir:
3216 isAutoDir = true;
3217 honoursRoot = false;
3218 break;
3219 case WheelDeltaAdjustmentStrategy::eAutoDirWithRootHonour:
3220 isAutoDir = true;
3221 honoursRoot = true;
3222 break;
3223 default:
3224 break;
3225 }
3226 }
3227
3228 if (aOptions & PREFER_MOUSE_WHEEL_TRANSACTION) {
3229 // If the user recently scrolled with the mousewheel, then they probably
3230 // want to scroll the same view as before instead of the view under the
3231 // cursor. WheelTransaction tracks the frame currently being
3232 // scrolled with the mousewheel. We consider the transaction ended when the
3233 // mouse moves more than "mousewheel.transaction.ignoremovedelay"
3234 // milliseconds after the last scroll operation, or any time the mouse moves
3235 // out of the frame, or when more than "mousewheel.transaction.timeout"
3236 // milliseconds have passed after the last operation, even if the mouse
3237 // hasn't moved.
3238 nsIFrame* lastScrollFrame = WheelTransaction::GetScrollTargetFrame();
3239 if (lastScrollFrame) {
3240 ScrollContainerFrame* scrollContainerFrame =
3241 lastScrollFrame->GetScrollTargetFrame();
3242 if (scrollContainerFrame) {
3243 if (isAutoDir) {
3244 ESMAutoDirWheelDeltaAdjuster adjuster(*aEvent, *lastScrollFrame,
3245 honoursRoot);
3246 // Note that calling this function will not always cause the delta to
3247 // be adjusted, it only adjusts the delta when it should, because
3248 // Adjust() internally calls ShouldBeAdjusted() before making
3249 // adjustment.
3250 adjuster.Adjust();
3251 }
3252 return scrollContainerFrame;
3253 }
3254 }
3255 }
3256
3257 // If the event doesn't cause scroll actually, we cannot find scroll target
3258 // because we check if the event can cause scroll actually on each found
3259 // scrollable frame.
3260 if (!aDirectionX && !aDirectionY) {
3261 return nullptr;
3262 }
3263
3264 bool checkIfScrollableX;
3265 bool checkIfScrollableY;
3266 if (isAutoDir) {
3267 // Always check the frame's scrollability in both the two directions for an
3268 // auto-dir scroll. That is, for an auto-dir scroll,
3269 // PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS and
3270 // PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS should be ignored.
3271 checkIfScrollableX = true;
3272 checkIfScrollableY = true;
3273 } else {
3274 checkIfScrollableX =
3275 aDirectionX &&
3276 (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS);
3277 checkIfScrollableY =
3278 aDirectionY &&
3279 (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS);
3280 }
3281
3282 nsIFrame* scrollFrame = !(aOptions & START_FROM_PARENT)
3283 ? aTargetFrame
3284 : GetParentFrameToScroll(aTargetFrame);
3285 for (; scrollFrame; scrollFrame = GetParentFrameToScroll(scrollFrame)) {
3286 // Check whether the frame wants to provide us with a scrollable view.
3287 ScrollContainerFrame* scrollContainerFrame =
3288 scrollFrame->GetScrollTargetFrame();
3289 if (!scrollContainerFrame) {
3290 nsMenuPopupFrame* menuPopupFrame = do_QueryFrame(scrollFrame);
3291 if (menuPopupFrame) {
3292 return nullptr;
3293 }
3294 continue;
3295 }
3296
3297 if (!checkIfScrollableX && !checkIfScrollableY) {
3298 return scrollContainerFrame;
3299 }
3300
3301 // If the frame disregards the direction the user is trying to scroll, then
3302 // it should just bubbles the scroll event up to its parental scroll frame
3303
3304 Maybe<layers::ScrollDirection> disregardedDirection =
3305 WheelHandlingUtils::GetDisregardedWheelScrollDirection(scrollFrame);
3306 if (disregardedDirection) {
3307 switch (disregardedDirection.ref()) {
3308 case layers::ScrollDirection::eHorizontal:
3309 if (checkIfScrollableX) {
3310 continue;
3311 }
3312 break;
3313 case layers::ScrollDirection::eVertical:
3314 if (checkIfScrollableY) {
3315 continue;
3316 }
3317 break;
3318 }
3319 }
3320
3321 layers::ScrollDirections directions =
3322 scrollContainerFrame
3323 ->GetAvailableScrollingDirectionsForUserInputEvents();
3324 if ((!(directions.contains(layers::ScrollDirection::eVertical)) &&
3325 !(directions.contains(layers::ScrollDirection::eHorizontal))) ||
3326 (checkIfScrollableY && !checkIfScrollableX &&
3327 !(directions.contains(layers::ScrollDirection::eVertical))) ||
3328 (checkIfScrollableX && !checkIfScrollableY &&
3329 !(directions.contains(layers::ScrollDirection::eHorizontal)))) {
3330 continue;
3331 }
3332
3333 // Computes whether the currently checked frame is scrollable by this wheel
3334 // event.
3335 bool canScroll = false;
3336 if (isAutoDir) {
3337 ESMAutoDirWheelDeltaAdjuster adjuster(*aEvent, *scrollFrame, honoursRoot);
3338 if (adjuster.ShouldBeAdjusted()) {
3339 adjuster.Adjust();
3340 canScroll = true;
3341 } else if (WheelHandlingUtils::CanScrollOn(scrollContainerFrame,
3342 aDirectionX, aDirectionY)) {
3343 canScroll = true;
3344 }
3345 } else if (WheelHandlingUtils::CanScrollOn(scrollContainerFrame,
3346 aDirectionX, aDirectionY)) {
3347 canScroll = true;
3348 }
3349
3350 if (canScroll) {
3351 return scrollContainerFrame;
3352 }
3353
3354 // Where we are at is the block ending in a for loop.
3355 // The current frame has been checked to be unscrollable by this wheel
3356 // event, continue the loop to check its parent, if any.
3357 }
3358
3359 nsIFrame* newFrame = nsLayoutUtils::GetCrossDocParentFrameInProcess(
3360 aTargetFrame->PresShell()->GetRootFrame());
3361 aOptions =
3362 static_cast<ComputeScrollTargetOptions>(aOptions & ~START_FROM_PARENT);
3363 if (!newFrame) {
3364 return nullptr;
3365 }
3366 return ComputeScrollTargetAndMayAdjustWheelEvent(newFrame, aEvent, aOptions);
3367}
3368
3369nsSize EventStateManager::GetScrollAmount(
3370 nsPresContext* aPresContext, WidgetWheelEvent* aEvent,
3371 ScrollContainerFrame* aScrollContainerFrame) {
3372 MOZ_ASSERT(aPresContext)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresContext))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPresContext", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3372); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresContext"
")"); do { *((volatile int*)__null) = 3372; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3373 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3373); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 3373; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3374
3375 const bool isPage = aEvent->mDeltaMode == WheelEvent_Binding::DOM_DELTA_PAGE;
3376 if (!aScrollContainerFrame) {
3377 // If there is no scrollable frame, we should use root, see below.
3378 aScrollContainerFrame =
3379 aPresContext->PresShell()->GetRootScrollContainerFrame();
3380 }
3381
3382 if (aScrollContainerFrame) {
3383 return isPage ? aScrollContainerFrame->GetPageScrollAmount()
3384 : aScrollContainerFrame->GetLineScrollAmount();
3385 }
3386
3387 // If there is no scrollable frame and page scrolling, use viewport size.
3388 if (isPage) {
3389 return aPresContext->GetVisibleArea().Size();
3390 }
3391
3392 // Otherwise use root frame's font metrics.
3393 //
3394 // FIXME(emilio): Should this use the root element's style frame? The root
3395 // frame will always have the initial font. Then again it should never matter
3396 // for content, we should always have a root scrollable frame in html
3397 // documents.
3398 nsIFrame* rootFrame = aPresContext->PresShell()->GetRootFrame();
3399 if (!rootFrame) {
3400 return nsSize(0, 0);
3401 }
3402 RefPtr<nsFontMetrics> fm =
3403 nsLayoutUtils::GetInflatedFontMetricsForFrame(rootFrame);
3404 NS_ENSURE_TRUE(fm, nsSize(0, 0))do { if ((__builtin_expect(!!(!(fm)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "fm" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3404); return nsSize(0, 0); } } while (false)
;
3405 return nsSize(fm->AveCharWidth(), fm->MaxHeight());
3406}
3407
3408void EventStateManager::DoScrollText(
3409 ScrollContainerFrame* aScrollContainerFrame, WidgetWheelEvent* aEvent) {
3410 MOZ_ASSERT(aScrollContainerFrame)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aScrollContainerFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aScrollContainerFrame))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aScrollContainerFrame"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3410); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aScrollContainerFrame"
")"); do { *((volatile int*)__null) = 3410; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3411 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3411); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 3411; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3412
3413 AutoWeakFrame scrollFrameWeak(aScrollContainerFrame);
3414 AutoWeakFrame eventFrameWeak(mCurrentTarget);
3415 if (!WheelTransaction::WillHandleDefaultAction(aEvent, scrollFrameWeak,
3416 eventFrameWeak)) {
3417 return;
3418 }
3419
3420 // Default action's actual scroll amount should be computed from device
3421 // pixels.
3422 nsPresContext* pc = aScrollContainerFrame->PresContext();
3423 nsSize scrollAmount = GetScrollAmount(pc, aEvent, aScrollContainerFrame);
3424 nsIntSize scrollAmountInDevPixels(
3425 pc->AppUnitsToDevPixels(scrollAmount.width),
3426 pc->AppUnitsToDevPixels(scrollAmount.height));
3427 nsIntPoint actualDevPixelScrollAmount =
3428 DeltaAccumulator::GetInstance()->ComputeScrollAmountForDefaultAction(
3429 aEvent, scrollAmountInDevPixels);
3430
3431 // Don't scroll around the axis whose overflow style is hidden.
3432 ScrollStyles overflowStyle = aScrollContainerFrame->GetScrollStyles();
3433 if (overflowStyle.mHorizontal == StyleOverflow::Hidden) {
3434 actualDevPixelScrollAmount.x = 0;
3435 }
3436 if (overflowStyle.mVertical == StyleOverflow::Hidden) {
3437 actualDevPixelScrollAmount.y = 0;
3438 }
3439
3440 ScrollSnapFlags snapFlags = ScrollSnapFlags::Disabled;
3441 mozilla::ScrollOrigin origin = mozilla::ScrollOrigin::NotSpecified;
3442 switch (aEvent->mDeltaMode) {
3443 case WheelEvent_Binding::DOM_DELTA_LINE:
3444 origin = mozilla::ScrollOrigin::MouseWheel;
3445 snapFlags = ScrollSnapFlags::IntendedDirection;
3446 break;
3447 case WheelEvent_Binding::DOM_DELTA_PAGE:
3448 origin = mozilla::ScrollOrigin::Pages;
3449 snapFlags = ScrollSnapFlags::IntendedDirection |
3450 ScrollSnapFlags::IntendedEndPosition;
3451 break;
3452 case WheelEvent_Binding::DOM_DELTA_PIXEL:
3453 origin = mozilla::ScrollOrigin::Pixels;
3454 break;
3455 default:
3456 MOZ_CRASH("Invalid deltaMode value comes")do { do { } while (false); MOZ_ReportCrash("" "Invalid deltaMode value comes"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3456); AnnotateMozCrashReason("MOZ_CRASH(" "Invalid deltaMode value comes"
")"); do { *((volatile int*)__null) = 3456; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
3457 }
3458
3459 // We shouldn't scroll more one page at once except when over one page scroll
3460 // is allowed for the event.
3461 nsSize pageSize = aScrollContainerFrame->GetPageScrollAmount();
3462 nsIntSize devPixelPageSize(pc->AppUnitsToDevPixels(pageSize.width),
3463 pc->AppUnitsToDevPixels(pageSize.height));
3464 if (!WheelPrefs::GetInstance()->IsOverOnePageScrollAllowedX(aEvent) &&
3465 DeprecatedAbs(actualDevPixelScrollAmount.x.value) >
3466 devPixelPageSize.width) {
3467 actualDevPixelScrollAmount.x = (actualDevPixelScrollAmount.x >= 0)
3468 ? devPixelPageSize.width
3469 : -devPixelPageSize.width;
3470 }
3471
3472 if (!WheelPrefs::GetInstance()->IsOverOnePageScrollAllowedY(aEvent) &&
3473 DeprecatedAbs(actualDevPixelScrollAmount.y.value) >
3474 devPixelPageSize.height) {
3475 actualDevPixelScrollAmount.y = (actualDevPixelScrollAmount.y >= 0)
3476 ? devPixelPageSize.height
3477 : -devPixelPageSize.height;
3478 }
3479
3480 bool isDeltaModePixel =
3481 (aEvent->mDeltaMode == WheelEvent_Binding::DOM_DELTA_PIXEL);
3482
3483 ScrollMode mode;
3484 switch (aEvent->mScrollType) {
3485 case WidgetWheelEvent::SCROLL_DEFAULT:
3486 if (isDeltaModePixel) {
3487 mode = ScrollMode::Normal;
3488 } else if (aEvent->mFlags.mHandledByAPZ) {
3489 mode = ScrollMode::SmoothMsd;
3490 } else {
3491 mode = ScrollMode::Smooth;
3492 }
3493 break;
3494 case WidgetWheelEvent::SCROLL_SYNCHRONOUSLY:
3495 mode = ScrollMode::Instant;
3496 break;
3497 case WidgetWheelEvent::SCROLL_ASYNCHRONOUSLY:
3498 mode = ScrollMode::Normal;
3499 break;
3500 case WidgetWheelEvent::SCROLL_SMOOTHLY:
3501 mode = ScrollMode::Smooth;
3502 break;
3503 default:
3504 MOZ_CRASH("Invalid mScrollType value comes")do { do { } while (false); MOZ_ReportCrash("" "Invalid mScrollType value comes"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3504); AnnotateMozCrashReason("MOZ_CRASH(" "Invalid mScrollType value comes"
")"); do { *((volatile int*)__null) = 3504; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
3505 }
3506
3507 ScrollContainerFrame::ScrollMomentum momentum =
3508 aEvent->mIsMomentum ? ScrollContainerFrame::SYNTHESIZED_MOMENTUM_EVENT
3509 : ScrollContainerFrame::NOT_MOMENTUM;
3510
3511 nsIntPoint overflow;
3512 aScrollContainerFrame->ScrollBy(actualDevPixelScrollAmount,
3513 ScrollUnit::DEVICE_PIXELS, mode, &overflow,
3514 origin, momentum, snapFlags);
3515
3516 if (!scrollFrameWeak.IsAlive()) {
3517 // If the scroll causes changing the layout, we can think that the event
3518 // has been completely consumed by the content. Then, users probably don't
3519 // want additional action.
3520 aEvent->mOverflowDeltaX = aEvent->mOverflowDeltaY = 0;
3521 } else if (isDeltaModePixel) {
3522 aEvent->mOverflowDeltaX = overflow.x;
3523 aEvent->mOverflowDeltaY = overflow.y;
3524 } else {
3525 aEvent->mOverflowDeltaX =
3526 static_cast<double>(overflow.x) / scrollAmountInDevPixels.width;
3527 aEvent->mOverflowDeltaY =
3528 static_cast<double>(overflow.y) / scrollAmountInDevPixels.height;
3529 }
3530
3531 // If CSS overflow properties caused not to scroll, the overflowDelta* values
3532 // should be same as delta* values since they may be used as gesture event by
3533 // widget. However, if there is another scrollable element in the ancestor
3534 // along the axis, probably users don't want the operation to cause
3535 // additional action such as moving history. In such case, overflowDelta
3536 // values should stay zero.
3537 if (scrollFrameWeak.IsAlive()) {
3538 if (aEvent->mDeltaX && overflowStyle.mHorizontal == StyleOverflow::Hidden &&
3539 !ComputeScrollTargetAndMayAdjustWheelEvent(
3540 aScrollContainerFrame, aEvent,
3541 COMPUTE_SCROLLABLE_ANCESTOR_ALONG_X_AXIS_WITH_AUTO_DIR)) {
3542 aEvent->mOverflowDeltaX = aEvent->mDeltaX;
3543 }
3544 if (aEvent->mDeltaY && overflowStyle.mVertical == StyleOverflow::Hidden &&
3545 !ComputeScrollTargetAndMayAdjustWheelEvent(
3546 aScrollContainerFrame, aEvent,
3547 COMPUTE_SCROLLABLE_ANCESTOR_ALONG_Y_AXIS_WITH_AUTO_DIR)) {
3548 aEvent->mOverflowDeltaY = aEvent->mDeltaY;
3549 }
3550 }
3551
3552 NS_ASSERTION(do { if (!(aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX
> 0) == (aEvent->mDeltaX > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaX is different from the scroll direction"
, "aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3555); MOZ_PretendNoReturn(); } } while (0)
3553 aEvent->mOverflowDeltaX == 0 ||do { if (!(aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX
> 0) == (aEvent->mDeltaX > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaX is different from the scroll direction"
, "aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3555); MOZ_PretendNoReturn(); } } while (0)
3554 (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0),do { if (!(aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX
> 0) == (aEvent->mDeltaX > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaX is different from the scroll direction"
, "aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3555); MOZ_PretendNoReturn(); } } while (0)
3555 "The sign of mOverflowDeltaX is different from the scroll direction")do { if (!(aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX
> 0) == (aEvent->mDeltaX > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaX is different from the scroll direction"
, "aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3555); MOZ_PretendNoReturn(); } } while (0)
;
3556 NS_ASSERTION(do { if (!(aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY
> 0) == (aEvent->mDeltaY > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaY is different from the scroll direction"
, "aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3559); MOZ_PretendNoReturn(); } } while (0)
3557 aEvent->mOverflowDeltaY == 0 ||do { if (!(aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY
> 0) == (aEvent->mDeltaY > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaY is different from the scroll direction"
, "aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3559); MOZ_PretendNoReturn(); } } while (0)
3558 (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0),do { if (!(aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY
> 0) == (aEvent->mDeltaY > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaY is different from the scroll direction"
, "aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3559); MOZ_PretendNoReturn(); } } while (0)
3559 "The sign of mOverflowDeltaY is different from the scroll direction")do { if (!(aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY
> 0) == (aEvent->mDeltaY > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaY is different from the scroll direction"
, "aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3559); MOZ_PretendNoReturn(); } } while (0)
;
3560
3561 WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(aEvent);
3562}
3563
3564void EventStateManager::DecideGestureEvent(WidgetGestureNotifyEvent* aEvent,
3565 nsIFrame* targetFrame) {
3566 NS_ASSERTION(aEvent->mMessage == eGestureNotify,do { if (!(aEvent->mMessage == eGestureNotify)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "DecideGestureEvent called with a non-gesture event"
, "aEvent->mMessage == eGestureNotify", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3567); MOZ_PretendNoReturn(); } } while (0)
3567 "DecideGestureEvent called with a non-gesture event")do { if (!(aEvent->mMessage == eGestureNotify)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "DecideGestureEvent called with a non-gesture event"
, "aEvent->mMessage == eGestureNotify", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3567); MOZ_PretendNoReturn(); } } while (0)
;
3568
3569 /* Check the ancestor tree to decide if any frame is willing* to receive
3570 * a MozPixelScroll event. If that's the case, the current touch gesture
3571 * will be used as a pan gesture; otherwise it will be a regular
3572 * mousedown/mousemove/click event.
3573 *
3574 * *willing: determine if it makes sense to pan the element using scroll
3575 * events:
3576 * - For web content: if there are any visible scrollbars on the touch point
3577 * - For XUL: if it's an scrollable element that can currently scroll in some
3578 * direction.
3579 *
3580 * Note: we'll have to one-off various cases to ensure a good usable behavior
3581 */
3582 WidgetGestureNotifyEvent::PanDirection panDirection =
3583 WidgetGestureNotifyEvent::ePanNone;
3584 bool displayPanFeedback = false;
3585 for (nsIFrame* current = targetFrame; current;
3586 current = nsLayoutUtils::GetCrossDocParentFrame(current)) {
3587 // e10s - mark remote content as pannable. This is a work around since
3588 // we don't have access to remote frame scroll info here. Apz data may
3589 // assist is solving this.
3590 if (current && IsTopLevelRemoteTarget(current->GetContent())) {
3591 panDirection = WidgetGestureNotifyEvent::ePanBoth;
3592 // We don't know when we reach bounds, so just disable feedback for now.
3593 displayPanFeedback = false;
3594 break;
3595 }
3596
3597 LayoutFrameType currentFrameType = current->Type();
3598
3599 // Scrollbars should always be draggable
3600 if (currentFrameType == LayoutFrameType::Scrollbar) {
3601 panDirection = WidgetGestureNotifyEvent::ePanNone;
3602 break;
3603 }
3604
3605 // Special check for trees
3606 if (nsTreeBodyFrame* treeFrame = do_QueryFrame(current)) {
3607 if (treeFrame->GetHorizontalOverflow()) {
3608 panDirection = WidgetGestureNotifyEvent::ePanHorizontal;
3609 }
3610 if (treeFrame->GetVerticalOverflow()) {
3611 panDirection = WidgetGestureNotifyEvent::ePanVertical;
3612 }
3613 break;
3614 }
3615
3616 if (ScrollContainerFrame* scrollContainerFrame = do_QueryFrame(current)) {
3617 layers::ScrollDirections scrollbarVisibility =
3618 scrollContainerFrame->GetScrollbarVisibility();
3619
3620 // Check if we have visible scrollbars
3621 if (scrollbarVisibility.contains(layers::ScrollDirection::eVertical)) {
3622 panDirection = WidgetGestureNotifyEvent::ePanVertical;
3623 displayPanFeedback = true;
3624 break;
3625 }
3626
3627 if (scrollbarVisibility.contains(layers::ScrollDirection::eHorizontal)) {
3628 panDirection = WidgetGestureNotifyEvent::ePanHorizontal;
3629 displayPanFeedback = true;
3630 }
3631 }
3632 } // ancestor chain
3633 aEvent->mDisplayPanFeedback = displayPanFeedback;
3634 aEvent->mPanDirection = panDirection;
3635}
3636
3637#ifdef XP_MACOSX
3638static nsINode* GetCrossDocParentNode(nsINode* aChild) {
3639 MOZ_ASSERT(aChild, "The child is null!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChild)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aChild))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aChild" " (" "The child is null!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3639); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild" ") ("
"The child is null!" ")"); do { *((volatile int*)__null) = 3639
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
3640 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3640); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 3640; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3641
3642 nsINode* parent = aChild->GetParentNode();
3643 if (parent && parent->IsContent() && aChild->IsContent()) {
3644 parent = aChild->AsContent()->GetFlattenedTreeParent();
3645 }
3646
3647 if (parent || !aChild->IsDocument()) {
3648 return parent;
3649 }
3650
3651 return aChild->AsDocument()->GetEmbedderElement();
3652}
3653
3654static bool NodeAllowsClickThrough(nsINode* aNode) {
3655 while (aNode) {
3656 if (aNode->IsAnyOfXULElements(nsGkAtoms::browser, nsGkAtoms::tree)) {
3657 return false;
3658 }
3659 if (aNode->IsAnyOfXULElements(nsGkAtoms::scrollbar, nsGkAtoms::resizer)) {
3660 return true;
3661 }
3662 aNode = GetCrossDocParentNode(aNode);
3663 }
3664 return true;
3665}
3666#endif
3667
3668void EventStateManager::PostHandleKeyboardEvent(
3669 WidgetKeyboardEvent* aKeyboardEvent, nsIFrame* aTargetFrame,
3670 nsEventStatus& aStatus) {
3671 if (aStatus == nsEventStatus_eConsumeNoDefault) {
3672 return;
3673 }
3674
3675 RefPtr<nsPresContext> presContext = mPresContext;
3676
3677 if (!aKeyboardEvent->HasBeenPostedToRemoteProcess()) {
3678 if (aKeyboardEvent->IsWaitingReplyFromRemoteProcess()) {
3679 RefPtr<BrowserParent> remote =
3680 aTargetFrame ? BrowserParent::GetFrom(aTargetFrame->GetContent())
3681 : nullptr;
3682 if (remote) {
3683 // remote is null-checked above in order to let pre-existing event
3684 // targeting code's chrome vs. content decision override in case of
3685 // disagreement in order not to disrupt non-Fission e10s mode in case
3686 // there are still bugs in the Fission-mode code. That is, if remote
3687 // is nullptr, the pre-existing event targeting code has deemed this
3688 // event to belong to chrome rather than content.
3689 BrowserParent* preciseRemote = BrowserParent::GetFocused();
3690 if (preciseRemote) {
3691 remote = preciseRemote;
3692 }
3693 // else there was a race between layout and focus tracking
3694 }
3695 if (remote && !remote->IsReadyToHandleInputEvents()) {
3696 // We need to dispatch the event to the browser element again if we were
3697 // waiting for the key reply but the event wasn't sent to the content
3698 // process due to the remote browser wasn't ready.
3699 WidgetKeyboardEvent keyEvent(*aKeyboardEvent);
3700 aKeyboardEvent->MarkAsHandledInRemoteProcess();
3701 RefPtr<Element> ownerElement = remote->GetOwnerElement();
3702 EventDispatcher::Dispatch(ownerElement, presContext, &keyEvent);
3703 if (keyEvent.DefaultPrevented()) {
3704 aKeyboardEvent->PreventDefault(!keyEvent.DefaultPreventedByContent());
3705 aStatus = nsEventStatus_eConsumeNoDefault;
3706 return;
3707 }
3708 }
3709 }
3710 // The widget expects a reply for every keyboard event. If the event wasn't
3711 // dispatched to a content process (non-e10s or no content process
3712 // running), we need to short-circuit here. Otherwise, we need to wait for
3713 // the content process to handle the event.
3714 if (aKeyboardEvent->mWidget) {
3715 aKeyboardEvent->mWidget->PostHandleKeyEvent(aKeyboardEvent);
3716 }
3717 if (aKeyboardEvent->DefaultPrevented()) {
3718 aStatus = nsEventStatus_eConsumeNoDefault;
3719 return;
3720 }
3721 }
3722
3723 // XXX Currently, our automated tests don't support mKeyNameIndex.
3724 // Therefore, we still need to handle this with keyCode.
3725 switch (aKeyboardEvent->mKeyCode) {
3726 case NS_VK_TAB:
3727 case NS_VK_F6:
3728 // This is to prevent keyboard scrolling while alt modifier in use.
3729 if (!aKeyboardEvent->IsAlt()) {
3730 aStatus = nsEventStatus_eConsumeNoDefault;
3731
3732 // Handling the tab event after it was sent to content is bad,
3733 // because to the FocusManager the remote-browser looks like one
3734 // element, so we would just move the focus to the next element
3735 // in chrome, instead of handling it in content.
3736 if (aKeyboardEvent->HasBeenPostedToRemoteProcess()) {
3737 break;
3738 }
3739
3740 EnsureDocument(presContext);
3741 nsFocusManager* fm = nsFocusManager::GetFocusManager();
3742 if (fm && mDocument) {
3743 // Shift focus forward or back depending on shift key
3744 bool isDocMove = aKeyboardEvent->IsControl() ||
3745 aKeyboardEvent->mKeyCode == NS_VK_F6;
3746 uint32_t dir =
3747 aKeyboardEvent->IsShift()
3748 ? (isDocMove ? static_cast<uint32_t>(
3749 nsIFocusManager::MOVEFOCUS_BACKWARDDOC)
3750 : static_cast<uint32_t>(
3751 nsIFocusManager::MOVEFOCUS_BACKWARD))
3752 : (isDocMove ? static_cast<uint32_t>(
3753 nsIFocusManager::MOVEFOCUS_FORWARDDOC)
3754 : static_cast<uint32_t>(
3755 nsIFocusManager::MOVEFOCUS_FORWARD));
3756 RefPtr<Element> result;
3757 fm->MoveFocus(mDocument->GetWindow(), nullptr, dir,
3758 nsIFocusManager::FLAG_BYKEY, getter_AddRefs(result));
3759 }
3760 }
3761 return;
3762 case 0:
3763 // We handle keys with no specific keycode value below.
3764 break;
3765 default:
3766 return;
3767 }
3768
3769 switch (aKeyboardEvent->mKeyNameIndex) {
3770 case KEY_NAME_INDEX_ZoomIn:
3771 case KEY_NAME_INDEX_ZoomOut:
3772 ChangeZoom(aKeyboardEvent->mKeyNameIndex == KEY_NAME_INDEX_ZoomIn);
3773 aStatus = nsEventStatus_eConsumeNoDefault;
3774 break;
3775 default:
3776 break;
3777 }
3778}
3779
3780static bool NeedsActiveContentChange(const WidgetMouseEvent* aMouseEvent) {
3781 // If the mouse event is a synthesized mouse event due to a touch, do
3782 // not set/clear the activation state. Element activation is handled by APZ.
3783 return !aMouseEvent ||
3784 aMouseEvent->mInputSource != MouseEvent_Binding::MOZ_SOURCE_TOUCH;
3785}
3786
3787nsresult EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
3788 WidgetEvent* aEvent,
3789 nsIFrame* aTargetFrame,
3790 nsEventStatus* aStatus,
3791 nsIContent* aOverrideClickTarget) {
3792 AUTO_PROFILER_LABEL("EventStateManager::PostHandleEvent", DOM)mozilla::AutoProfilerLabel raiiObject3792( "EventStateManager::PostHandleEvent"
, nullptr, JS::ProfilingCategoryPair::DOM)
;
3793 NS_ENSURE_ARG(aPresContext)do { if ((__builtin_expect(!!(!(aPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3793); return NS_ERROR_INVALID_ARG; } } while (false)
;
3794 NS_ENSURE_ARG_POINTER(aStatus)do { if ((__builtin_expect(!!(!(aStatus)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStatus" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3794); return NS_ERROR_INVALID_POINTER; } } while (false)
;
3795
3796 mCurrentTarget = aTargetFrame;
3797 mCurrentTargetContent = nullptr;
3798
3799 HandleCrossProcessEvent(aEvent, aStatus);
3800 // NOTE: the above call may have destroyed aTargetFrame, please use
3801 // mCurrentTarget henceforth. This is to avoid using it accidentally:
3802 aTargetFrame = nullptr;
3803
3804 // Most of the events we handle below require a frame.
3805 // Add special cases here.
3806 if (!mCurrentTarget && aEvent->mMessage != eMouseUp &&
3807 aEvent->mMessage != eMouseDown && aEvent->mMessage != eDragEnter &&
3808 aEvent->mMessage != eDragOver && aEvent->mMessage != ePointerUp &&
3809 aEvent->mMessage != ePointerCancel) {
3810 return NS_OK;
3811 }
3812
3813 // Keep the prescontext alive, we might need it after event dispatch
3814 RefPtr<nsPresContext> presContext = aPresContext;
3815 nsresult ret = NS_OK;
3816
3817 switch (aEvent->mMessage) {
3818 case eMouseDown: {
3819 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
3820 if (mouseEvent->mButton == MouseButton::ePrimary &&
3821 !sNormalLMouseEventInProcess) {
3822 // We got a mouseup event while a mousedown event was being processed.
3823 // Make sure that the capturing content is cleared.
3824 PresShell::ReleaseCapturingContent();
3825 break;
3826 }
3827
3828 // For remote content, capture the event in the parent process at the
3829 // <xul:browser remote> element. This will ensure that subsequent
3830 // mousemove/mouseup events will continue to be dispatched to this element
3831 // and therefore forwarded to the child.
3832 if (aEvent->HasBeenPostedToRemoteProcess() &&
3833 !PresShell::GetCapturingContent()) {
3834 if (nsIContent* content =
3835 mCurrentTarget ? mCurrentTarget->GetContent() : nullptr) {
3836 PresShell::SetCapturingContent(content, CaptureFlags::None, aEvent);
3837 } else {
3838 PresShell::ReleaseCapturingContent();
3839 }
3840 }
3841
3842 // If MouseEvent::PreventClickEvent() was called by chrome script,
3843 // we need to forget the clicking content and click count for the
3844 // following eMouseUp event.
3845 if (mouseEvent->mClickEventPrevented) {
3846 switch (mouseEvent->mButton) {
3847 case MouseButton::ePrimary:
3848 case MouseButton::eSecondary:
3849 case MouseButton::eMiddle: {
3850 LastMouseDownInfo& mouseDownInfo =
3851 GetLastMouseDownInfo(mouseEvent->mButton);
3852 mouseDownInfo.mLastMouseDownContent = nullptr;
3853 mouseDownInfo.mClickCount = 0;
3854 mouseDownInfo.mLastMouseDownInputControlType = Nothing();
3855 break;
3856 }
3857
3858 default:
3859 break;
3860 }
3861 }
3862
3863 nsCOMPtr<nsIContent> activeContent;
3864 // When content calls PreventDefault on pointerdown, we also call
3865 // PreventDefault on the subsequent mouse events to suppress default
3866 // behaviors. Normally, aStatus should be nsEventStatus_eConsumeNoDefault
3867 // when the event is DefaultPrevented but it's reset to
3868 // nsEventStatus_eIgnore in EventStateManager::PreHandleEvent. So we also
3869 // check if the event is DefaultPrevented.
3870 if (nsEventStatus_eConsumeNoDefault != *aStatus &&
3871 !aEvent->DefaultPrevented()) {
3872 nsCOMPtr<nsIContent> newFocus;
3873 bool suppressBlur = false;
3874 if (mCurrentTarget) {
3875 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(newFocus));
3876 activeContent = mCurrentTarget->GetContent();
3877
3878 // In some cases, we do not want to even blur the current focused
3879 // element. Those cases are:
3880 // 1. -moz-user-focus CSS property is set to 'ignore';
3881 // 2. XUL control element has the disabled property set to 'true'.
3882 //
3883 // We can't use nsIFrame::IsFocusable() because we want to blur when
3884 // we click on a visibility: none element.
3885 // We can't use nsIContent::IsFocusable() because we want to blur when
3886 // we click on a non-focusable element like a <div>.
3887 // We have to use |aEvent->mTarget| to not make sure we do not check
3888 // an anonymous node of the targeted element.
3889 suppressBlur =
3890 mCurrentTarget->StyleUI()->UserFocus() == StyleUserFocus::Ignore;
3891
3892 if (!suppressBlur) {
3893 if (Element* element =
3894 Element::FromEventTargetOrNull(aEvent->mTarget)) {
3895 if (nsCOMPtr<nsIDOMXULControlElement> xulControl =
3896 element->AsXULControl()) {
3897 bool disabled = false;
3898 xulControl->GetDisabled(&disabled);
3899 suppressBlur = disabled;
3900 }
3901 }
3902 }
3903 }
3904
3905 // When a root content which isn't editable but has an editable HTML
3906 // <body> element is clicked, we should redirect the focus to the
3907 // the <body> element. E.g., when an user click bottom of the editor
3908 // where is outside of the <body> element, the <body> should be focused
3909 // and the user can edit immediately after that.
3910 //
3911 // NOTE: The newFocus isn't editable that also means it's not in
3912 // designMode. In designMode, all contents are not focusable.
3913 if (newFocus && !newFocus->IsEditable()) {
3914 Document* doc = newFocus->GetComposedDoc();
3915 if (doc && newFocus == doc->GetRootElement()) {
3916 nsIContent* bodyContent =
3917 nsLayoutUtils::GetEditableRootContentByContentEditable(doc);
3918 if (bodyContent && bodyContent->GetPrimaryFrame()) {
3919 newFocus = bodyContent;
3920 }
3921 }
3922 }
3923
3924 // When the mouse is pressed, the default action is to focus the
3925 // target. Look for the nearest enclosing focusable frame.
3926 //
3927 // TODO: Probably this should be moved to Element::PostHandleEvent.
3928 for (; newFocus; newFocus = newFocus->GetFlattenedTreeParent()) {
3929 if (!newFocus->IsElement()) {
3930 continue;
3931 }
3932
3933 nsIFrame* frame = newFocus->GetPrimaryFrame();
3934 if (!frame) {
3935 continue;
3936 }
3937
3938 // If the mousedown happened inside a popup, don't try to set focus on
3939 // one of its containing elements
3940 if (frame->IsMenuPopupFrame()) {
3941 newFocus = nullptr;
3942 break;
3943 }
3944
3945 auto flags = IsFocusableFlags::WithMouse;
3946 if (frame->IsFocusable(flags)) {
3947 break;
3948 }
3949
3950 if (ShadowRoot* root = newFocus->GetShadowRoot()) {
3951 if (root->DelegatesFocus()) {
3952 if (Element* firstFocusable = root->GetFocusDelegate(flags)) {
3953 newFocus = firstFocusable;
3954 break;
3955 }
3956 }
3957 }
3958 }
3959
3960 MOZ_ASSERT_IF(newFocus, newFocus->IsElement())do { if (newFocus) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(newFocus->IsElement())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(newFocus->IsElement()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("newFocus->IsElement()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3960); AnnotateMozCrashReason("MOZ_ASSERT" "(" "newFocus->IsElement()"
")"); do { *((volatile int*)__null) = 3960; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
3961
3962 if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
3963 // if something was found to focus, focus it. Otherwise, if the
3964 // element that was clicked doesn't have -moz-user-focus: ignore,
3965 // clear the existing focus. For -moz-user-focus: ignore, the focus
3966 // is just left as is.
3967 // Another effect of mouse clicking, handled in Selection, is that
3968 // it should update the caret position to where the mouse was
3969 // clicked. Because the focus is cleared when clicking on a
3970 // non-focusable node, the next press of the tab key will cause
3971 // focus to be shifted from the caret position instead of the root.
3972 if (newFocus) {
3973 // use the mouse flag and the noscroll flag so that the content
3974 // doesn't unexpectedly scroll when clicking an element that is
3975 // only half visible
3976 uint32_t flags =
3977 nsIFocusManager::FLAG_BYMOUSE | nsIFocusManager::FLAG_NOSCROLL;
3978 // If this was a touch-generated event, pass that information:
3979 if (mouseEvent->mInputSource ==
3980 MouseEvent_Binding::MOZ_SOURCE_TOUCH) {
3981 flags |= nsIFocusManager::FLAG_BYTOUCH;
3982 }
3983 fm->SetFocus(MOZ_KnownLive(newFocus->AsElement())(newFocus->AsElement()), flags);
3984 } else if (!suppressBlur) {
3985 // clear the focus within the frame and then set it as the
3986 // focused frame
3987 EnsureDocument(mPresContext);
3988 if (mDocument) {
3989 nsCOMPtr<nsPIDOMWindowOuter> outerWindow = mDocument->GetWindow();
3990#ifdef XP_MACOSX
3991 if (!activeContent || !activeContent->IsXULElement())
3992#endif
3993 fm->ClearFocus(outerWindow);
3994 // Prevent switch frame if we're already not in the foreground tab
3995 // and we're in a content process.
3996 // TODO: If we were inactive frame in this tab, and now in
3997 // background tab, we shouldn't make the tab foreground, but
3998 // we should set focus to clicked document in the background
3999 // tab. However, nsFocusManager does not have proper method
4000 // for doing this. Therefore, we should skip setting focus
4001 // to clicked document for now.
4002 if (XRE_IsParentProcess() || IsInActiveTab(mDocument)) {
4003 fm->SetFocusedWindow(outerWindow);
4004 }
4005 }
4006 }
4007 }
4008
4009 // The rest is left button-specific.
4010 if (mouseEvent->mButton != MouseButton::ePrimary) {
4011 break;
4012 }
4013
4014 // The nearest enclosing element goes into the :active state. If we're
4015 // not an element (so we're text or something) we need to obtain
4016 // our parent element and put it into :active instead.
4017 if (activeContent && !activeContent->IsElement()) {
4018 if (nsIContent* par = activeContent->GetFlattenedTreeParent()) {
4019 activeContent = par;
4020 }
4021 }
4022 } else {
4023 // if we're here, the event handler returned false, so stop
4024 // any of our own processing of a drag. Workaround for bug 43258.
4025 StopTrackingDragGesture(true);
4026 }
4027 // XXX Why do we always set this is active? Active window may be changed
4028 // by a mousedown event listener.
4029 if (NeedsActiveContentChange(mouseEvent)) {
4030 SetActiveManager(this, activeContent);
4031 }
4032 } break;
4033 case ePointerCancel:
4034 case ePointerUp: {
4035 WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent();
4036 MOZ_ASSERT(pointerEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(pointerEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pointerEvent))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("pointerEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4036); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pointerEvent"
")"); do { *((volatile int*)__null) = 4036; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4037 // Implicitly releasing capture for given pointer. ePointerLostCapture
4038 // should be send after ePointerUp or ePointerCancel.
4039 PointerEventHandler::ImplicitlyReleasePointerCapture(pointerEvent);
4040 PointerEventHandler::UpdateActivePointerState(pointerEvent);
4041
4042 if (
4043 // After pointercancel, pointer becomes invalid so we can remove
4044 // relevant helper from table.
4045 pointerEvent->mMessage == ePointerCancel ||
4046 // pointerup for non-hoverable pointer needs to dispatch pointerout
4047 // and pointerleave events because the pointer is valid only while the
4048 // pointer is "down".
4049 !pointerEvent->InputSourceSupportsHover()) {
4050 GenerateMouseEnterExit(pointerEvent);
4051 mPointersEnterLeaveHelper.Remove(pointerEvent->pointerId);
4052 }
4053
4054 break;
4055 }
4056 case eMouseUp: {
4057 // We can unconditionally stop capturing because
4058 // we should never be capturing when the mouse button is up
4059 PresShell::ReleaseCapturingContent();
4060
4061 WidgetMouseEvent* mouseUpEvent = aEvent->AsMouseEvent();
4062 if (NeedsActiveContentChange(mouseUpEvent)) {
4063 ClearGlobalActiveContent(this);
4064 }
4065 if (mouseUpEvent && EventCausesClickEvents(*mouseUpEvent)) {
4066 // Make sure to dispatch the click even if there is no frame for
4067 // the current target element. This is required for Web compatibility.
4068 RefPtr<EventStateManager> esm =
4069 ESMFromContentOrThis(aOverrideClickTarget);
4070 ret =
4071 esm->PostHandleMouseUp(mouseUpEvent, aStatus, aOverrideClickTarget);
4072 }
4073
4074 if (PresShell* presShell = presContext->GetPresShell()) {
4075 RefPtr<nsFrameSelection> frameSelection = presShell->FrameSelection();
4076 frameSelection->SetDragState(false);
4077 }
4078 } break;
4079 case eWheelOperationEnd: {
4080 MOZ_ASSERT(aEvent->IsTrusted())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->IsTrusted())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->IsTrusted()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->IsTrusted()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4080); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsTrusted()"
")"); do { *((volatile int*)__null) = 4080; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4081 ScrollbarsForWheel::MayInactivate();
4082 WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
4083 ScrollContainerFrame* scrollTarget =
4084 ComputeScrollTargetAndMayAdjustWheelEvent(
4085 mCurrentTarget, wheelEvent,
4086 COMPUTE_DEFAULT_ACTION_TARGET_WITH_AUTO_DIR);
4087 // If the wheel event was handled by APZ, APZ will perform the scroll
4088 // snap.
4089 if (scrollTarget && !WheelTransaction::HandledByApz()) {
4090 scrollTarget->ScrollSnap();
4091 }
4092 } break;
4093 case eWheel:
4094 case eWheelOperationStart: {
4095 MOZ_ASSERT(aEvent->IsTrusted())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->IsTrusted())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->IsTrusted()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->IsTrusted()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4095); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsTrusted()"
")"); do { *((volatile int*)__null) = 4095; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4096
4097 if (*aStatus == nsEventStatus_eConsumeNoDefault) {
4098 ScrollbarsForWheel::Inactivate();
4099 break;
4100 }
4101
4102 WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
4103 MOZ_ASSERT(wheelEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(wheelEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(wheelEvent))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("wheelEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4103); AnnotateMozCrashReason("MOZ_ASSERT" "(" "wheelEvent"
")"); do { *((volatile int*)__null) = 4103; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4104
4105 // When APZ is enabled, the actual scroll animation might be handled by
4106 // the compositor.
4107 WheelPrefs::Action action =
4108 wheelEvent->mFlags.mHandledByAPZ
4109 ? WheelPrefs::ACTION_NONE
4110 : WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent);
4111
4112 WheelDeltaAdjustmentStrategy strategy =
4113 GetWheelDeltaAdjustmentStrategy(*wheelEvent);
4114 // Adjust the delta values of the wheel event if the current default
4115 // action is to horizontalize scrolling. I.e., deltaY values are set to
4116 // deltaX and deltaY and deltaZ values are set to 0.
4117 // If horizontalized, the delta values will be restored and its overflow
4118 // deltaX will become 0 when the WheelDeltaHorizontalizer instance is
4119 // being destroyed.
4120 WheelDeltaHorizontalizer horizontalizer(*wheelEvent);
4121 if (WheelDeltaAdjustmentStrategy::eHorizontalize == strategy) {
4122 horizontalizer.Horizontalize();
4123 }
4124
4125 // Since ComputeScrollTargetAndMayAdjustWheelEvent() may adjust the delta
4126 // if the event is auto-dir. So we use |ESMAutoDirWheelDeltaRestorer|
4127 // here.
4128 // An instance of |ESMAutoDirWheelDeltaRestorer| is used to monitor
4129 // auto-dir adjustment which may happen during its lifetime. If the delta
4130 // values is adjusted during its lifetime, the instance will restore the
4131 // adjusted delta when it's being destrcuted.
4132 ESMAutoDirWheelDeltaRestorer restorer(*wheelEvent);
4133 ScrollContainerFrame* scrollTarget =
4134 ComputeScrollTargetAndMayAdjustWheelEvent(
4135 mCurrentTarget, wheelEvent,
4136 COMPUTE_DEFAULT_ACTION_TARGET_WITH_AUTO_DIR);
4137
4138 switch (action) {
4139 case WheelPrefs::ACTION_SCROLL:
4140 case WheelPrefs::ACTION_HORIZONTALIZED_SCROLL: {
4141 // For scrolling of default action, we should honor the mouse wheel
4142 // transaction.
4143
4144 ScrollbarsForWheel::PrepareToScrollText(this, mCurrentTarget,
4145 wheelEvent);
4146
4147 if (aEvent->mMessage != eWheel ||
4148 (!wheelEvent->mDeltaX && !wheelEvent->mDeltaY)) {
4149 break;
4150 }
4151
4152 ScrollbarsForWheel::SetActiveScrollTarget(scrollTarget);
4153
4154 ScrollContainerFrame* rootScrollContainerFrame =
4155 !mCurrentTarget
4156 ? nullptr
4157 : mCurrentTarget->PresShell()->GetRootScrollContainerFrame();
4158 if (!scrollTarget || scrollTarget == rootScrollContainerFrame) {
4159 wheelEvent->mViewPortIsOverscrolled = true;
4160 }
4161 wheelEvent->mOverflowDeltaX = wheelEvent->mDeltaX;
4162 wheelEvent->mOverflowDeltaY = wheelEvent->mDeltaY;
4163 WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(
4164 wheelEvent);
4165 if (scrollTarget) {
4166 DoScrollText(scrollTarget, wheelEvent);
4167 } else {
4168 WheelTransaction::EndTransaction();
4169 ScrollbarsForWheel::Inactivate();
4170 }
4171 break;
4172 }
4173 case WheelPrefs::ACTION_HISTORY: {
4174 // If this event doesn't cause eLegacyMouseLineOrPageScroll event or
4175 // the direction is oblique, don't perform history back/forward.
4176 int32_t intDelta = wheelEvent->GetPreferredIntDelta();
4177 if (!intDelta) {
4178 break;
4179 }
4180 DoScrollHistory(intDelta);
4181 break;
4182 }
4183 case WheelPrefs::ACTION_ZOOM: {
4184 // If this event doesn't cause eLegacyMouseLineOrPageScroll event or
4185 // the direction is oblique, don't perform zoom in/out.
4186 int32_t intDelta = wheelEvent->GetPreferredIntDelta();
4187 if (!intDelta) {
4188 break;
4189 }
4190 DoScrollZoom(mCurrentTarget, intDelta);
4191 break;
4192 }
4193 case WheelPrefs::ACTION_NONE:
4194 default:
4195 bool allDeltaOverflown = false;
4196 if (StaticPrefs::dom_event_wheel_event_groups_enabled() &&
4197 (wheelEvent->mDeltaX != 0.0 || wheelEvent->mDeltaY != 0.0)) {
4198 if (scrollTarget) {
4199 WheelTransaction::WillHandleDefaultAction(
4200 wheelEvent, scrollTarget, mCurrentTarget);
4201 } else {
4202 WheelTransaction::EndTransaction();
4203 }
4204 }
4205 if (wheelEvent->mFlags.mHandledByAPZ) {
4206 if (wheelEvent->mCanTriggerSwipe) {
4207 // For events that can trigger swipes, APZ needs to know whether
4208 // scrolling is possible in the requested direction. It does this
4209 // by looking at the scroll overflow values on mCanTriggerSwipe
4210 // events after they have been processed.
4211 allDeltaOverflown = !ComputeScrollTarget(
4212 mCurrentTarget, wheelEvent, COMPUTE_DEFAULT_ACTION_TARGET);
4213 }
4214 } else {
4215 // The event was processed neither by APZ nor by us, so all of the
4216 // delta values must be overflown delta values.
4217 allDeltaOverflown = true;
4218 }
4219
4220 if (!allDeltaOverflown) {
4221 break;
4222 }
4223 wheelEvent->mOverflowDeltaX = wheelEvent->mDeltaX;
4224 wheelEvent->mOverflowDeltaY = wheelEvent->mDeltaY;
4225 WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(
4226 wheelEvent);
4227 wheelEvent->mViewPortIsOverscrolled = true;
4228 break;
4229 }
4230 *aStatus = nsEventStatus_eConsumeNoDefault;
4231 } break;
4232
4233 case eGestureNotify: {
4234 if (nsEventStatus_eConsumeNoDefault != *aStatus) {
4235 DecideGestureEvent(aEvent->AsGestureNotifyEvent(), mCurrentTarget);
4236 }
4237 } break;
4238
4239 case eDragEnter:
4240 case eDragOver: {
4241 NS_ASSERTION(aEvent->mClass == eDragEventClass, "Expected a drag event")do { if (!(aEvent->mClass == eDragEventClass)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Expected a drag event", "aEvent->mClass == eDragEventClass"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4241); MOZ_PretendNoReturn(); } } while (0)
;
4242
4243 // Check if the drag is occurring inside a scrollable area. If so, scroll
4244 // the area when the mouse is near the edges.
4245 if (mCurrentTarget && aEvent->mMessage == eDragOver) {
4246 nsIFrame* checkFrame = mCurrentTarget;
4247 while (checkFrame) {
4248 ScrollContainerFrame* scrollFrame = do_QueryFrame(checkFrame);
4249 // Break out so only the innermost scrollframe is scrolled.
4250 if (scrollFrame && scrollFrame->DragScroll(aEvent)) {
4251 break;
4252 }
4253 checkFrame = checkFrame->GetParent();
4254 }
4255 }
4256
4257 nsCOMPtr<nsIDragSession> dragSession =
4258 nsContentUtils::GetDragSession(mPresContext);
4259 if (!dragSession) break;
4260
4261 // Reset the flag.
4262 dragSession->SetOnlyChromeDrop(false);
4263 if (mPresContext) {
4264 EnsureDocument(mPresContext);
4265 }
4266 bool isChromeDoc = nsContentUtils::IsChromeDoc(mDocument);
4267
4268 // the initial dataTransfer is the one from the dragstart event that
4269 // was set on the dragSession when the drag began.
4270 RefPtr<DataTransfer> dataTransfer;
4271 RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer();
4272
4273 WidgetDragEvent* dragEvent = aEvent->AsDragEvent();
4274
4275 // collect any changes to moz cursor settings stored in the event's
4276 // data transfer.
4277 UpdateDragDataTransfer(dragEvent);
4278
4279 // cancelling a dragenter or dragover event means that a drop should be
4280 // allowed, so update the dropEffect and the canDrop state to indicate
4281 // that a drag is allowed. If the event isn't cancelled, a drop won't be
4282 // allowed. Essentially, to allow a drop somewhere, specify the effects
4283 // using the effectAllowed and dropEffect properties in a dragenter or
4284 // dragover event and cancel the event. To not allow a drop somewhere,
4285 // don't cancel the event or set the effectAllowed or dropEffect to
4286 // "none". This way, if the event is just ignored, no drop will be
4287 // allowed.
4288 uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
4289 uint32_t action = nsIDragService::DRAGDROP_ACTION_NONE;
4290 if (nsEventStatus_eConsumeNoDefault == *aStatus) {
4291 // If the event has initialized its mDataTransfer, use it.
4292 // Or the event has not been initialized its mDataTransfer, but
4293 // it's set before dispatch because of synthesized, but without
4294 // testing session (e.g., emulating drag from another app), use it
4295 // coming from outside.
4296 // XXX Perhaps, for the latter case, we need new API because we don't
4297 // have a chance to initialize allowed effects of the session.
4298 if (dragEvent->mDataTransfer) {
4299 // get the dataTransfer and the dropEffect that was set on it
4300 dataTransfer = dragEvent->mDataTransfer;
4301 dropEffect = dataTransfer->DropEffectInt();
4302 } else {
4303 // if dragEvent->mDataTransfer is null, it means that no attempt was
4304 // made to access the dataTransfer during the event, yet the event
4305 // was cancelled. Instead, use the initial data transfer available
4306 // from the drag session. The drop effect would not have been
4307 // initialized (which is done in DragEvent::GetDataTransfer),
4308 // so set it from the drag action. We'll still want to filter it
4309 // based on the effectAllowed below.
4310 dataTransfer = initialDataTransfer;
4311
4312 dragSession->GetDragAction(&action);
4313
4314 // filter the drop effect based on the action. Use UNINITIALIZED as
4315 // any effect is allowed.
4316 dropEffect = nsContentUtils::FilterDropEffect(
4317 action, nsIDragService::DRAGDROP_ACTION_UNINITIALIZED);
4318 }
4319
4320 // At this point, if the dataTransfer is null, it means that the
4321 // drag was originally started by directly calling the drag service.
4322 // Just assume that all effects are allowed.
4323 uint32_t effectAllowed = nsIDragService::DRAGDROP_ACTION_UNINITIALIZED;
4324 if (dataTransfer) {
4325 effectAllowed = dataTransfer->EffectAllowedInt();
4326 }
4327
4328 // set the drag action based on the drop effect and effect allowed.
4329 // The drop effect field on the drag transfer object specifies the
4330 // desired current drop effect. However, it cannot be used if the
4331 // effectAllowed state doesn't include that type of action. If the
4332 // dropEffect is "none", then the action will be 'none' so a drop will
4333 // not be allowed.
4334 if (effectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED ||
4335 dropEffect & effectAllowed)
4336 action = dropEffect;
4337
4338 if (action == nsIDragService::DRAGDROP_ACTION_NONE)
4339 dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
4340
4341 // inform the drag session that a drop is allowed on this node.
4342 dragSession->SetDragAction(action);
4343 dragSession->SetCanDrop(action != nsIDragService::DRAGDROP_ACTION_NONE);
4344
4345 // For now, do this only for dragover.
4346 // XXXsmaug dragenter needs some more work.
4347 if (aEvent->mMessage == eDragOver && !isChromeDoc) {
4348 // Someone has called preventDefault(), check whether is was on
4349 // content or chrome.
4350 dragSession->SetOnlyChromeDrop(
4351 !dragEvent->mDefaultPreventedOnContent);
4352 }
4353 } else if (aEvent->mMessage == eDragOver && !isChromeDoc) {
4354 // No one called preventDefault(), so handle drop only in chrome.
4355 dragSession->SetOnlyChromeDrop(true);
4356 }
4357 if (auto* bc = BrowserChild::GetFrom(presContext->GetDocShell())) {
4358 bc->SendUpdateDropEffect(action, dropEffect);
4359 }
4360 if (aEvent->HasBeenPostedToRemoteProcess()) {
4361 dragSession->SetCanDrop(true);
4362 } else if (initialDataTransfer) {
4363 // Now set the drop effect in the initial dataTransfer. This ensures
4364 // that we can get the desired drop effect in the drop event. For events
4365 // dispatched to content, the content process will take care of setting
4366 // this.
4367 initialDataTransfer->SetDropEffectInt(dropEffect);
4368 }
4369 } break;
4370
4371 case eDrop: {
4372 if (aEvent->mFlags.mIsSynthesizedForTests) {
4373 nsCOMPtr<nsIDragService> dragService =
4374 do_GetService("@mozilla.org/widget/dragservice;1");
4375 nsCOMPtr<nsIDragSession> dragSession =
4376 nsContentUtils::GetDragSession(mPresContext);
4377 if (dragSession && dragService &&
4378 !dragService->GetNeverAllowSessionIsSynthesizedForTests()) {
4379 MOZ_ASSERT(dragSession->IsSynthesizedForTests())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(dragSession->IsSynthesizedForTests())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(dragSession->IsSynthesizedForTests()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("dragSession->IsSynthesizedForTests()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4379); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dragSession->IsSynthesizedForTests()"
")"); do { *((volatile int*)__null) = 4379; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4380 RefPtr<WindowContext> sourceWC;
4381 DebugOnly<nsresult> rvIgnored =
4382 dragSession->GetSourceWindowContext(getter_AddRefs(sourceWC));
4383 NS_WARNING_ASSERTION(do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "nsIDragSession::GetSourceDocument() failed, but ignored"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4385); } } while (false)
4384 NS_SUCCEEDED(rvIgnored),do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "nsIDragSession::GetSourceDocument() failed, but ignored"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4385); } } while (false)
4385 "nsIDragSession::GetSourceDocument() failed, but ignored")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "nsIDragSession::GetSourceDocument() failed, but ignored"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4385); } } while (false)
;
4386 // If the drag source hasn't been initialized, i.e., dragstart was
4387 // consumed by the test, the test needs to dispatch "dragend" event
4388 // instead of the drag session. Therefore, it does not make sense
4389 // to set drag end point in such case (you hit assersion if you do
4390 // it).
4391 if (sourceWC) {
4392 CSSIntPoint dropPointInScreen =
4393 Event::GetScreenCoords(aPresContext, aEvent, aEvent->mRefPoint)
4394 .extract();
4395 dragSession->SetDragEndPointForTests(dropPointInScreen.x,
4396 dropPointInScreen.y);
4397 }
4398 }
4399 }
4400 sLastDragOverFrame = nullptr;
4401 ClearGlobalActiveContent(this);
4402 break;
4403 }
4404 case eDragExit: {
4405 // make sure to fire the enter and exit_synth events after the
4406 // eDragExit event, otherwise we'll clean up too early
4407 GenerateDragDropEnterExit(presContext, aEvent->AsDragEvent());
4408 if (auto* bc = BrowserChild::GetFrom(presContext->GetDocShell())) {
4409 // SendUpdateDropEffect to prevent nsIDragService from waiting for
4410 // response of forwarded dragexit event.
4411 bc->SendUpdateDropEffect(nsIDragService::DRAGDROP_ACTION_NONE,
4412 nsIDragService::DRAGDROP_ACTION_NONE);
4413 }
4414 break;
4415 }
4416 case eKeyUp:
4417 // If space key is released, we need to inactivate the element which was
4418 // activated by preceding space key down.
4419 // XXX Currently, we don't store the reason of activation. Therefore,
4420 // this may cancel what is activated by a mousedown, but it must not
4421 // cause actual problem in web apps in the wild since it must be
4422 // rare case that users release space key during a mouse click/drag.
4423 if (aEvent->AsKeyboardEvent()->ShouldWorkAsSpaceKey()) {
4424 ClearGlobalActiveContent(this);
4425 }
4426 break;
4427
4428 case eKeyPress: {
4429 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
4430 PostHandleKeyboardEvent(keyEvent, mCurrentTarget, *aStatus);
4431 } break;
4432
4433 case eMouseEnterIntoWidget:
4434 if (mCurrentTarget) {
4435 nsCOMPtr<nsIContent> targetContent;
4436 mCurrentTarget->GetContentForEvent(aEvent,
4437 getter_AddRefs(targetContent));
4438 SetContentState(targetContent, ElementState::HOVER);
4439 }
4440 break;
4441
4442 case eMouseExitFromWidget:
4443 PointerEventHandler::UpdateActivePointerState(aEvent->AsMouseEvent());
4444 break;
4445
4446#ifdef XP_MACOSX
4447 case eMouseActivate:
4448 if (mCurrentTarget) {
4449 nsCOMPtr<nsIContent> targetContent;
4450 mCurrentTarget->GetContentForEvent(aEvent,
4451 getter_AddRefs(targetContent));
4452 if (!NodeAllowsClickThrough(targetContent)) {
4453 *aStatus = nsEventStatus_eConsumeNoDefault;
4454 }
4455 }
4456 break;
4457#endif
4458
4459 default:
4460 break;
4461 }
4462
4463 // Reset target frame to null to avoid mistargeting after reentrant event
4464 mCurrentTarget = nullptr;
4465 mCurrentTargetContent = nullptr;
4466
4467 return ret;
4468}
4469
4470BrowserParent* EventStateManager::GetCrossProcessTarget() {
4471 return IMEStateManager::GetActiveBrowserParent();
4472}
4473
4474bool EventStateManager::IsTargetCrossProcess(WidgetGUIEvent* aEvent) {
4475 // Check to see if there is a focused, editable content in chrome,
4476 // in that case, do not forward IME events to content
4477 Element* focusedElement = GetFocusedElement();
4478 if (focusedElement && focusedElement->IsEditable()) {
4479 return false;
4480 }
4481 return IMEStateManager::GetActiveBrowserParent() != nullptr;
4482}
4483
4484void EventStateManager::NotifyDestroyPresContext(nsPresContext* aPresContext) {
4485 RefPtr<nsPresContext> presContext = aPresContext;
4486 if (presContext) {
4487 IMEStateManager::OnDestroyPresContext(*presContext);
4488 }
4489
4490 // Bug 70855: Presentation is going away, possibly for a reframe.
4491 // Reset the hover state so that if we're recreating the presentation,
4492 // we won't have the old hover state still set in the new presentation,
4493 // as if the new presentation is resized, a new element may be hovered.
4494 ResetHoverState();
4495
4496 mMouseEnterLeaveHelper = nullptr;
4497 mPointersEnterLeaveHelper.Clear();
4498 PointerEventHandler::NotifyDestroyPresContext(presContext);
4499}
4500
4501void EventStateManager::ResetHoverState() {
4502 if (mHoverContent) {
4503 SetContentState(nullptr, ElementState::HOVER);
4504 }
4505}
4506
4507void EventStateManager::SetPresContext(nsPresContext* aPresContext) {
4508 mPresContext = aPresContext;
4509}
4510
4511void EventStateManager::ClearFrameRefs(nsIFrame* aFrame) {
4512 if (aFrame && aFrame == mCurrentTarget) {
4513 mCurrentTargetContent = aFrame->GetContent();
4514 }
4515}
4516
4517struct CursorImage {
4518 gfx::IntPoint mHotspot;
4519 nsCOMPtr<imgIContainer> mContainer;
4520 ImageResolution mResolution;
4521 bool mEarlierCursorLoading = false;
4522};
4523
4524// Given the event that we're processing, and the computed cursor and hotspot,
4525// determine whether the custom CSS cursor should be blocked (that is, not
4526// honored).
4527//
4528// We will not honor it all of the following are true:
4529//
4530// * the size of the custom cursor is bigger than layout.cursor.block.max-size.
4531// * the bounds of the cursor would end up outside of the viewport of the
4532// top-level content document.
4533//
4534// This is done in order to prevent hijacking the cursor, see bug 1445844 and
4535// co.
4536static bool ShouldBlockCustomCursor(nsPresContext* aPresContext,
4537 WidgetEvent* aEvent,
4538 const CursorImage& aCursor) {
4539 int32_t width = 0;
4540 int32_t height = 0;
4541 aCursor.mContainer->GetWidth(&width);
4542 aCursor.mContainer->GetHeight(&height);
4543 aCursor.mResolution.ApplyTo(width, height);
4544
4545 int32_t maxSize = StaticPrefs::layout_cursor_block_max_size();
4546
4547 if (width <= maxSize && height <= maxSize) {
4548 return false;
4549 }
4550
4551 auto input = DOMIntersectionObserver::ComputeInput(*aPresContext->Document(),
4552 nullptr, nullptr);
4553
4554 if (!input.mRootFrame) {
4555 return false;
4556 }
4557
4558 nsPoint point = nsLayoutUtils::GetEventCoordinatesRelativeTo(
4559 aEvent, RelativeTo{input.mRootFrame});
4560
4561 // The cursor size won't be affected by our full zoom in the parent process,
4562 // so undo that before checking the rect.
4563 float zoom = aPresContext->GetFullZoom();
4564
4565 // Also adjust for accessibility cursor scaling factor.
4566 zoom /= LookAndFeel::GetFloat(LookAndFeel::FloatID::CursorScale, 1.0f);
4567
4568 nsSize size(CSSPixel::ToAppUnits(width / zoom),
4569 CSSPixel::ToAppUnits(height / zoom));
4570 nsPoint hotspot(
4571 CSSPixel::ToAppUnits(ViewAs<CSSPixel>(aCursor.mHotspot.x / zoom)),
4572 CSSPixel::ToAppUnits(ViewAs<CSSPixel>(aCursor.mHotspot.y / zoom)));
4573
4574 const nsRect cursorRect(point - hotspot, size);
4575 auto output = DOMIntersectionObserver::Intersect(input, cursorRect);
4576 return !output.mIntersectionRect ||
4577 !(*output.mIntersectionRect == cursorRect);
4578}
4579
4580static gfx::IntPoint ComputeHotspot(imgIContainer* aContainer,
4581 const Maybe<gfx::Point>& aHotspot) {
4582 MOZ_ASSERT(aContainer)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContainer)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aContainer))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aContainer", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4582); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContainer"
")"); do { *((volatile int*)__null) = 4582; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4583
4584 // css3-ui says to use the CSS-specified hotspot if present,
4585 // otherwise use the intrinsic hotspot, otherwise use the top left
4586 // corner.
4587 if (aHotspot) {
4588 int32_t imgWidth, imgHeight;
4589 aContainer->GetWidth(&imgWidth);
4590 aContainer->GetHeight(&imgHeight);
4591 auto hotspot = gfx::IntPoint::Round(*aHotspot);
4592 return {std::max(std::min(hotspot.x.value, imgWidth - 1), 0),
4593 std::max(std::min(hotspot.y.value, imgHeight - 1), 0)};
4594 }
4595
4596 gfx::IntPoint hotspot;
4597 aContainer->GetHotspotX(&hotspot.x.value);
4598 aContainer->GetHotspotY(&hotspot.y.value);
4599 return hotspot;
4600}
4601
4602static CursorImage ComputeCustomCursor(nsPresContext* aPresContext,
4603 WidgetEvent* aEvent,
4604 const nsIFrame& aFrame,
4605 const nsIFrame::Cursor& aCursor) {
4606 if (aCursor.mAllowCustomCursor == nsIFrame::AllowCustomCursorImage::No) {
4607 return {};
4608 }
4609 const ComputedStyle& style =
4610 aCursor.mStyle ? *aCursor.mStyle : *aFrame.Style();
4611
4612 // If we are falling back because any cursor before us is loading, let the
4613 // consumer know.
4614 bool loading = false;
4615 for (const auto& image : style.StyleUI()->Cursor().images.AsSpan()) {
4616 MOZ_ASSERT(image.image.IsImageRequestType(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(image.image.IsImageRequestType())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(image.image.IsImageRequestType
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("image.image.IsImageRequestType()" " (" "Cursor image should only parse url() types"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4617); AnnotateMozCrashReason("MOZ_ASSERT" "(" "image.image.IsImageRequestType()"
") (" "Cursor image should only parse url() types" ")"); do {
*((volatile int*)__null) = 4617; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
4617 "Cursor image should only parse url() types")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(image.image.IsImageRequestType())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(image.image.IsImageRequestType
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("image.image.IsImageRequestType()" " (" "Cursor image should only parse url() types"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4617); AnnotateMozCrashReason("MOZ_ASSERT" "(" "image.image.IsImageRequestType()"
") (" "Cursor image should only parse url() types" ")"); do {
*((volatile int*)__null) = 4617; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
4618 uint32_t status;
4619 imgRequestProxy* req = image.image.GetImageRequest();
4620 if (!req || NS_FAILED(req->GetImageStatus(&status))((bool)(__builtin_expect(!!(NS_FAILED_impl(req->GetImageStatus
(&status))), 0)))
) {
4621 continue;
4622 }
4623 if (!(status & imgIRequest::STATUS_LOAD_COMPLETE)) {
4624 loading = true;
4625 continue;
4626 }
4627 if (status & imgIRequest::STATUS_ERROR) {
4628 continue;
4629 }
4630 nsCOMPtr<imgIContainer> container;
4631 req->GetImage(getter_AddRefs(container));
4632 if (!container) {
4633 continue;
4634 }
4635 StyleImageOrientation orientation =
4636 aFrame.StyleVisibility()->UsedImageOrientation(req);
4637 container = nsLayoutUtils::OrientImage(container, orientation);
4638 Maybe<gfx::Point> specifiedHotspot =
4639 image.has_hotspot ? Some(gfx::Point{image.hotspot_x, image.hotspot_y})
4640 : Nothing();
4641 gfx::IntPoint hotspot = ComputeHotspot(container, specifiedHotspot);
4642 CursorImage result{hotspot, std::move(container),
4643 image.image.GetResolution(style), loading};
4644 if (ShouldBlockCustomCursor(aPresContext, aEvent, result)) {
4645 continue;
4646 }
4647 // This is the one we want!
4648 return result;
4649 }
4650 return {{}, nullptr, {}, loading};
4651}
4652
4653void EventStateManager::UpdateCursor(nsPresContext* aPresContext,
4654 WidgetMouseEvent* aEvent,
4655 nsIFrame* aTargetFrame,
4656 nsEventStatus* aStatus) {
4657 if (aTargetFrame && IsRemoteTarget(aTargetFrame->GetContent())) {
4658 return;
4659 }
4660
4661 auto cursor = StyleCursorKind::Default;
4662 nsCOMPtr<imgIContainer> container;
4663 ImageResolution resolution;
4664 Maybe<gfx::IntPoint> hotspot;
4665
4666 if (mHidingCursorWhileTyping && aEvent->IsReal()) {
4667 // Any non-synthetic mouse event makes us show the cursor again.
4668 mHidingCursorWhileTyping = false;
4669 }
4670
4671 if (mHidingCursorWhileTyping) {
4672 cursor = StyleCursorKind::None;
4673 } else if (mLockCursor != kInvalidCursorKind) {
4674 // If cursor is locked just use the locked one
4675 cursor = mLockCursor;
4676 } else if (aTargetFrame) {
4677 // If not locked, look for correct cursor
4678 nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(
4679 aEvent, RelativeTo{aTargetFrame});
4680 const nsIFrame::Cursor framecursor = aTargetFrame->GetCursor(pt);
4681 const CursorImage customCursor =
4682 ComputeCustomCursor(aPresContext, aEvent, *aTargetFrame, framecursor);
4683
4684 // If the current cursor is from the same frame, and it is now
4685 // loading some new image for the cursor, we should wait for a
4686 // while rather than taking its fallback cursor directly.
4687 if (customCursor.mEarlierCursorLoading &&
4688 gLastCursorSourceFrame == aTargetFrame &&
4689 TimeStamp::NowLoRes() - gLastCursorUpdateTime <
4690 TimeDuration::FromMilliseconds(kCursorLoadingTimeout)) {
4691 return;
4692 }
4693 cursor = framecursor.mCursor;
4694 container = std::move(customCursor.mContainer);
4695 resolution = customCursor.mResolution;
4696 hotspot = Some(customCursor.mHotspot);
4697 }
4698
4699 if (aTargetFrame) {
4700 if (cursor == StyleCursorKind::Pointer && IsSelectingLink(aTargetFrame)) {
4701 cursor = aTargetFrame->GetWritingMode().IsVertical()
4702 ? StyleCursorKind::VerticalText
4703 : StyleCursorKind::Text;
4704 }
4705 SetCursor(cursor, container, resolution, hotspot,
4706 aTargetFrame->GetNearestWidget(), false);
4707 gLastCursorSourceFrame = aTargetFrame;
4708 gLastCursorUpdateTime = TimeStamp::NowLoRes();
4709 }
4710
4711 if (mLockCursor != kInvalidCursorKind || StyleCursorKind::Auto != cursor) {
4712 *aStatus = nsEventStatus_eConsumeDoDefault;
4713 }
4714}
4715
4716void EventStateManager::ClearCachedWidgetCursor(nsIFrame* aTargetFrame) {
4717 if (!aTargetFrame) {
4718 return;
4719 }
4720 nsIWidget* aWidget = aTargetFrame->GetNearestWidget();
4721 if (!aWidget) {
4722 return;
4723 }
4724 aWidget->ClearCachedCursor();
4725}
4726
4727void EventStateManager::StartHidingCursorWhileTyping(nsIWidget* aWidget) {
4728 if (mHidingCursorWhileTyping || sCursorSettingManager != this) {
4729 return;
4730 }
4731 mHidingCursorWhileTyping = true;
4732 SetCursor(StyleCursorKind::None, nullptr, {}, {}, aWidget, false);
4733}
4734
4735nsresult EventStateManager::SetCursor(StyleCursorKind aCursor,
4736 imgIContainer* aContainer,
4737 const ImageResolution& aResolution,
4738 const Maybe<gfx::IntPoint>& aHotspot,
4739 nsIWidget* aWidget, bool aLockCursor) {
4740 EnsureDocument(mPresContext);
4741 NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(mDocument)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mDocument" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4741); return NS_ERROR_FAILURE; } } while (false)
;
4742 sCursorSettingManager = this;
4743
4744 NS_ENSURE_TRUE(aWidget, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(aWidget)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aWidget" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4744); return NS_ERROR_FAILURE; } } while (false)
;
4745 if (aLockCursor) {
4746 if (StyleCursorKind::Auto != aCursor) {
4747 mLockCursor = aCursor;
4748 } else {
4749 // If cursor style is set to auto we unlock the cursor again.
4750 mLockCursor = kInvalidCursorKind;
4751 }
4752 }
4753 nsCursor c;
4754 switch (aCursor) {
4755 case StyleCursorKind::Auto:
4756 case StyleCursorKind::Default:
4757 c = eCursor_standard;
4758 break;
4759 case StyleCursorKind::Pointer:
4760 c = eCursor_hyperlink;
4761 break;
4762 case StyleCursorKind::Crosshair:
4763 c = eCursor_crosshair;
4764 break;
4765 case StyleCursorKind::Move:
4766 c = eCursor_move;
4767 break;
4768 case StyleCursorKind::Text:
4769 c = eCursor_select;
4770 break;
4771 case StyleCursorKind::Wait:
4772 c = eCursor_wait;
4773 break;
4774 case StyleCursorKind::Help:
4775 c = eCursor_help;
4776 break;
4777 case StyleCursorKind::NResize:
4778 c = eCursor_n_resize;
4779 break;
4780 case StyleCursorKind::SResize:
4781 c = eCursor_s_resize;
4782 break;
4783 case StyleCursorKind::WResize:
4784 c = eCursor_w_resize;
4785 break;
4786 case StyleCursorKind::EResize:
4787 c = eCursor_e_resize;
4788 break;
4789 case StyleCursorKind::NwResize:
4790 c = eCursor_nw_resize;
4791 break;
4792 case StyleCursorKind::SeResize:
4793 c = eCursor_se_resize;
4794 break;
4795 case StyleCursorKind::NeResize:
4796 c = eCursor_ne_resize;
4797 break;
4798 case StyleCursorKind::SwResize:
4799 c = eCursor_sw_resize;
4800 break;
4801 case StyleCursorKind::Copy: // CSS3
4802 c = eCursor_copy;
4803 break;
4804 case StyleCursorKind::Alias:
4805 c = eCursor_alias;
4806 break;
4807 case StyleCursorKind::ContextMenu:
4808 c = eCursor_context_menu;
4809 break;
4810 case StyleCursorKind::Cell:
4811 c = eCursor_cell;
4812 break;
4813 case StyleCursorKind::Grab:
4814 c = eCursor_grab;
4815 break;
4816 case StyleCursorKind::Grabbing:
4817 c = eCursor_grabbing;
4818 break;
4819 case StyleCursorKind::Progress:
4820 c = eCursor_spinning;
4821 break;
4822 case StyleCursorKind::ZoomIn:
4823 c = eCursor_zoom_in;
4824 break;
4825 case StyleCursorKind::ZoomOut:
4826 c = eCursor_zoom_out;
4827 break;
4828 case StyleCursorKind::NotAllowed:
4829 c = eCursor_not_allowed;
4830 break;
4831 case StyleCursorKind::ColResize:
4832 c = eCursor_col_resize;
4833 break;
4834 case StyleCursorKind::RowResize:
4835 c = eCursor_row_resize;
4836 break;
4837 case StyleCursorKind::NoDrop:
4838 c = eCursor_no_drop;
4839 break;
4840 case StyleCursorKind::VerticalText:
4841 c = eCursor_vertical_text;
4842 break;
4843 case StyleCursorKind::AllScroll:
4844 c = eCursor_all_scroll;
4845 break;
4846 case StyleCursorKind::NeswResize:
4847 c = eCursor_nesw_resize;
4848 break;
4849 case StyleCursorKind::NwseResize:
4850 c = eCursor_nwse_resize;
4851 break;
4852 case StyleCursorKind::NsResize:
4853 c = eCursor_ns_resize;
4854 break;
4855 case StyleCursorKind::EwResize:
4856 c = eCursor_ew_resize;
4857 break;
4858 case StyleCursorKind::None:
4859 c = eCursor_none;
4860 break;
4861 default:
4862 MOZ_ASSERT_UNREACHABLE("Unknown cursor kind")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Unknown cursor kind" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4862); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unknown cursor kind" ")"); do { *
((volatile int*)__null) = 4862; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
4863 c = eCursor_standard;
4864 break;
4865 }
4866
4867 uint32_t x = aHotspot ? aHotspot->x.value : 0;
4868 uint32_t y = aHotspot ? aHotspot->y.value : 0;
4869 aWidget->SetCursor(nsIWidget::Cursor{c, aContainer, x, y, aResolution});
4870 return NS_OK;
4871}
4872
4873bool EventStateManager::CursorSettingManagerHasLockedCursor() {
4874 return sCursorSettingManager &&
4875 sCursorSettingManager->mLockCursor != kInvalidCursorKind;
4876}
4877
4878class MOZ_STACK_CLASS ESMEventCB : public EventDispatchingCallback {
4879 public:
4880 explicit ESMEventCB(nsIContent* aTarget) : mTarget(aTarget) {}
4881
4882 MOZ_CAN_RUN_SCRIPT
4883 void HandleEvent(EventChainPostVisitor& aVisitor) override {
4884 if (aVisitor.mPresContext) {
4885 nsIFrame* frame = aVisitor.mPresContext->GetPrimaryFrameFor(mTarget);
4886 if (frame) {
4887 frame->HandleEvent(aVisitor.mPresContext, aVisitor.mEvent->AsGUIEvent(),
4888 &aVisitor.mEventStatus);
4889 }
4890 }
4891 }
4892
4893 nsCOMPtr<nsIContent> mTarget;
4894};
4895
4896static UniquePtr<WidgetMouseEvent> CreateMouseOrPointerWidgetEvent(
4897 WidgetMouseEvent* aMouseEvent, EventMessage aMessage,
4898 EventTarget* aRelatedTarget) {
4899 // This method does not support creating a mouse/pointer button change event
4900 // because of no data about the changing state.
4901 MOZ_ASSERT(aMessage != eMouseDown)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage != eMouseDown)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage != eMouseDown))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aMessage != eMouseDown"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4901); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != eMouseDown"
")"); do { *((volatile int*)__null) = 4901; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4902 MOZ_ASSERT(aMessage != eMouseUp)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage != eMouseUp)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage != eMouseUp))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("aMessage != eMouseUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4902); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != eMouseUp"
")"); do { *((volatile int*)__null) = 4902; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4903 MOZ_ASSERT(aMessage != ePointerDown)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage != ePointerDown)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage != ePointerDown))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aMessage != ePointerDown"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4903); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != ePointerDown"
")"); do { *((volatile int*)__null) = 4903; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4904 MOZ_ASSERT(aMessage != ePointerUp)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage != ePointerUp)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage != ePointerUp))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aMessage != ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4904); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != ePointerUp"
")"); do { *((volatile int*)__null) = 4904; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4905 // This method is currently designed to create the following events.
4906 MOZ_ASSERT(aMessage == eMouseOver || aMessage == eMouseEnter ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4911); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4911; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4907 aMessage == eMouseOut || aMessage == eMouseLeave ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4911); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4911; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4908 aMessage == ePointerOver || aMessage == ePointerEnter ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4911); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4911; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4909 aMessage == ePointerOut || aMessage == ePointerLeave ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4911); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4911; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4910 aMessage == eMouseEnterIntoWidget ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4911); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4911; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4911 aMessage == eMouseExitFromWidget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4911); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4911; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4912
4913 WidgetPointerEvent* sourcePointer = aMouseEvent->AsPointerEvent();
4914 UniquePtr<WidgetMouseEvent> newEvent;
4915 if (sourcePointer) {
4916 AUTO_PROFILER_LABEL("CreateMouseOrPointerWidgetEvent", OTHER)mozilla::AutoProfilerLabel raiiObject4916( "CreateMouseOrPointerWidgetEvent"
, nullptr, JS::ProfilingCategoryPair::OTHER)
;
4917
4918 WidgetPointerEvent* newPointerEvent = new WidgetPointerEvent(
4919 aMouseEvent->IsTrusted(), aMessage, aMouseEvent->mWidget);
4920 newPointerEvent->mIsPrimary = sourcePointer->mIsPrimary;
4921 newPointerEvent->mWidth = sourcePointer->mWidth;
4922 newPointerEvent->mHeight = sourcePointer->mHeight;
4923 newPointerEvent->mInputSource = sourcePointer->mInputSource;
4924
4925 newEvent = WrapUnique(newPointerEvent);
4926 } else {
4927 newEvent = MakeUnique<WidgetMouseEvent>(aMouseEvent->IsTrusted(), aMessage,
4928 aMouseEvent->mWidget,
4929 WidgetMouseEvent::eReal);
4930 }
4931
4932 // Inherit whether the event is synthesized by the test API or not.
4933 // Then, when the event is synthesized by a test API and handled in a remote
4934 // process, it won't be ignored. See PresShell::HandleEvent().
4935 newEvent->mFlags.mIsSynthesizedForTests =
4936 aMouseEvent->mFlags.mIsSynthesizedForTests;
4937
4938 newEvent->mRelatedTarget = aRelatedTarget;
4939 newEvent->mRefPoint = aMouseEvent->mRefPoint;
4940 newEvent->mModifiers = aMouseEvent->mModifiers;
4941 if (!aMouseEvent->mFlags.mDispatchedAtLeastOnce &&
4942 aMouseEvent->InputSourceSupportsHover()) {
4943 // If we synthesize a pointer event or a mouse event from another event
4944 // which changes a button state whose input soucre supports hover state and
4945 // the source event has not been dispatched yet, we should set to the button
4946 // state of the synthesizing event to previous one.
4947 // Note that we don't need to do this if the input source does not support
4948 // hover state because a WPT check the behavior (see below) and the other
4949 // browsers pass the test even though this is inconsistent behavior.
4950 newEvent->mButton =
4951 sourcePointer ? MouseButton::eNotPressed : MouseButton::ePrimary;
4952 if (aMouseEvent->IsPressingButton()) {
4953 // If the source event has not been dispatched into the DOM yet, we
4954 // need to remove the flag which is being pressed.
4955 newEvent->mButtons = static_cast<decltype(WidgetMouseEvent::mButtons)>(
4956 aMouseEvent->mButtons &
4957 ~MouseButtonsFlagToChange(
4958 static_cast<MouseButton>(aMouseEvent->mButton)));
4959 } else if (aMouseEvent->IsReleasingButton()) {
4960 // If the source event has not been dispatched into the DOM yet, we
4961 // need to add the flag which is being released.
4962 newEvent->mButtons = static_cast<decltype(WidgetMouseEvent::mButtons)>(
4963 aMouseEvent->mButtons |
4964 MouseButtonsFlagToChange(
4965 static_cast<MouseButton>(aMouseEvent->mButton)));
4966 } else {
4967 // The source event does not change the buttons state so that we can
4968 // set mButtons value as-is.
4969 newEvent->mButtons = aMouseEvent->mButtons;
4970 }
4971 // Adjust pressure if it does not matches with mButtons.
4972 // FIXME: We may use wrong pressure value if the source event has not been
4973 // dispatched into the DOM yet. However, fixing this requires to store the
4974 // last pressure value somewhere.
4975 if (newEvent->mButtons && aMouseEvent->mPressure == 0) {
4976 newEvent->mPressure = 0.5f;
4977 } else if (!newEvent->mButtons && aMouseEvent->mPressure != 0) {
4978 newEvent->mPressure = 0;
4979 } else {
4980 newEvent->mPressure = aMouseEvent->mPressure;
4981 }
4982 } else {
4983 // If the event has already been dispatched into the tree, web apps has
4984 // already handled the button state change, so the button state of the
4985 // source event has already synced.
4986 // If the input source does not have hover state, we don't need to modify
4987 // the state because the other browsers behave so and tested by
4988 // pointerevent_attributes_nohover_pointers.html even though this is
4989 // different expectation from
4990 // pointerevent_attributes_hoverable_pointers.html, but the other browsers
4991 // pass both of them.
4992 newEvent->mButton = aMouseEvent->mButton;
4993 newEvent->mButtons = aMouseEvent->mButtons;
4994 newEvent->mPressure = aMouseEvent->mPressure;
4995 }
4996
4997 newEvent->mInputSource = aMouseEvent->mInputSource;
4998 newEvent->pointerId = aMouseEvent->pointerId;
4999
5000 return newEvent;
5001}
5002
5003already_AddRefed<nsIWidget>
5004EventStateManager::DispatchMouseOrPointerBoundaryEvent(
5005 WidgetMouseEvent* aMouseEvent, EventMessage aMessage,
5006 nsIContent* aTargetContent, nsIContent* aRelatedContent) {
5007 MOZ_ASSERT(aMessage == eMouseEnter || aMessage == ePointerEnter ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseEnter || aMessage == ePointerEnter
|| aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage
== eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut
|| aMessage == ePointerOut)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseEnter || aMessage
== ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave
|| aMessage == eMouseOver || aMessage == ePointerOver || aMessage
== eMouseOut || aMessage == ePointerOut))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5010); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5010; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5008 aMessage == eMouseLeave || aMessage == ePointerLeave ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseEnter || aMessage == ePointerEnter
|| aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage
== eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut
|| aMessage == ePointerOut)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseEnter || aMessage
== ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave
|| aMessage == eMouseOver || aMessage == ePointerOver || aMessage
== eMouseOut || aMessage == ePointerOut))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5010); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5010; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5009 aMessage == eMouseOver || aMessage == ePointerOver ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseEnter || aMessage == ePointerEnter
|| aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage
== eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut
|| aMessage == ePointerOut)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseEnter || aMessage
== ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave
|| aMessage == eMouseOver || aMessage == ePointerOver || aMessage
== eMouseOut || aMessage == ePointerOut))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5010); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5010; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5010 aMessage == eMouseOut || aMessage == ePointerOut)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseEnter || aMessage == ePointerEnter
|| aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage
== eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut
|| aMessage == ePointerOut)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseEnter || aMessage
== ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave
|| aMessage == eMouseOver || aMessage == ePointerOver || aMessage
== eMouseOut || aMessage == ePointerOut))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5010); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5010; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5011
5012 // https://w3c.github.io/pointerlock/#dom-element-requestpointerlock
5013 // "[Once in the locked state...E]vents that require the concept
5014 // of a mouse cursor must not be dispatched (for example: mouseover,
5015 // mouseout...).
5016 // XXXedgar should we also block pointer events?
5017 if (PointerLockManager::IsLocked() &&
5018 (aMessage == eMouseLeave || aMessage == eMouseEnter ||
5019 aMessage == eMouseOver || aMessage == eMouseOut)) {
5020 mCurrentTargetContent = nullptr;
5021 nsCOMPtr<Element> pointerLockedElement =
5022 PointerLockManager::GetLockedElement();
5023 if (!pointerLockedElement) {
5024 NS_WARNING("Should have pointer locked element, but didn't.")NS_DebugBreak(NS_DEBUG_WARNING, "Should have pointer locked element, but didn't."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5024)
;
5025 return nullptr;
5026 }
5027 nsIFrame* const pointerLockedFrame =
5028 mPresContext->GetPrimaryFrameFor(pointerLockedElement);
5029 if (NS_WARN_IF(!pointerLockedFrame)NS_warn_if_impl(!pointerLockedFrame, "!pointerLockedFrame", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5029)
) {
5030 return nullptr;
5031 }
5032 return do_AddRef(pointerLockedFrame->GetNearestWidget());
5033 }
5034
5035 mCurrentTargetContent = nullptr;
5036
5037 if (!aTargetContent) {
5038 return nullptr;
5039 }
5040
5041 // Store the widget before dispatching the event because some event listeners
5042 // of the dispatching event may cause reframe the target or remove the target
5043 // from the tree.
5044 nsCOMPtr<nsIWidget> targetWidget;
5045 if (nsIFrame* const targetFrame =
5046 mPresContext->GetPrimaryFrameFor(aTargetContent)) {
5047 targetWidget = targetFrame->GetNearestWidget();
5048 }
5049
5050 nsCOMPtr<nsIContent> targetContent = aTargetContent;
5051 nsCOMPtr<nsIContent> relatedContent = aRelatedContent;
5052
5053 UniquePtr<WidgetMouseEvent> dispatchEvent =
5054 CreateMouseOrPointerWidgetEvent(aMouseEvent, aMessage, relatedContent);
5055
5056 AutoWeakFrame previousTarget = mCurrentTarget;
5057 mCurrentTargetContent = targetContent;
5058
5059 nsEventStatus status = nsEventStatus_eIgnore;
5060 ESMEventCB callback(targetContent);
5061 RefPtr<nsPresContext> presContext = mPresContext;
5062 EventDispatcher::Dispatch(targetContent, presContext, dispatchEvent.get(),
5063 nullptr, &status, &callback);
5064
5065 if (mPresContext) {
5066 // If we are entering/leaving remote content, dispatch a mouse enter/exit
5067 // event to the remote frame.
5068 if (IsTopLevelRemoteTarget(targetContent)) {
5069 if (aMessage == eMouseOut) {
5070 // For remote content, send a puppet widget mouse exit event.
5071 UniquePtr<WidgetMouseEvent> remoteEvent =
5072 CreateMouseOrPointerWidgetEvent(aMouseEvent, eMouseExitFromWidget,
5073 relatedContent);
5074 remoteEvent->mExitFrom = Some(WidgetMouseEvent::ePuppet);
5075
5076 // mCurrentTarget is set to the new target, so we must reset it to the
5077 // old target and then dispatch a cross-process event. (mCurrentTarget
5078 // will be set back below.) HandleCrossProcessEvent will query for the
5079 // proper target via GetEventTarget which will return mCurrentTarget.
5080 mCurrentTarget = mPresContext->GetPrimaryFrameFor(targetContent);
5081 HandleCrossProcessEvent(remoteEvent.get(), &status);
5082 } else if (aMessage == eMouseOver) {
5083 UniquePtr<WidgetMouseEvent> remoteEvent =
5084 CreateMouseOrPointerWidgetEvent(aMouseEvent, eMouseEnterIntoWidget,
5085 relatedContent);
5086 HandleCrossProcessEvent(remoteEvent.get(), &status);
5087 }
5088 }
5089 }
5090
5091 mCurrentTargetContent = nullptr;
5092 mCurrentTarget = previousTarget;
5093
5094 return targetWidget.forget();
5095}
5096
5097static nsIContent* FindCommonAncestor(nsIContent* aNode1, nsIContent* aNode2) {
5098 if (!aNode1 || !aNode2) {
5099 return nullptr;
5100 }
5101 return nsContentUtils::GetCommonFlattenedTreeAncestor(aNode1, aNode2);
5102}
5103
5104class EnterLeaveDispatcher {
5105 public:
5106 EnterLeaveDispatcher(EventStateManager* aESM, nsIContent* aTarget,
5107 nsIContent* aRelatedTarget,
5108 WidgetMouseEvent* aMouseEvent,
5109 EventMessage aEventMessage)
5110 : mESM(aESM), mMouseEvent(aMouseEvent), mEventMessage(aEventMessage) {
5111 nsPIDOMWindowInner* win =
5112 aTarget ? aTarget->OwnerDoc()->GetInnerWindow() : nullptr;
5113 if (aMouseEvent->AsPointerEvent()
5114 ? win && win->HasPointerEnterLeaveEventListeners()
5115 : win && win->HasMouseEnterLeaveEventListeners()) {
5116 mRelatedTarget =
5117 aRelatedTarget ? aRelatedTarget->FindFirstNonChromeOnlyAccessContent()
5118 : nullptr;
5119 nsINode* commonParent = FindCommonAncestor(aTarget, aRelatedTarget);
5120 nsIContent* current = aTarget;
5121 // Note, it is ok if commonParent is null!
5122 while (current && current != commonParent) {
5123 if (!current->ChromeOnlyAccess()) {
5124 mTargets.AppendObject(current);
5125 }
5126 // mouseenter/leave is fired only on elements.
5127 current = current->GetFlattenedTreeParent();
5128 }
5129 }
5130 }
5131
5132 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
5133 MOZ_CAN_RUN_SCRIPT_BOUNDARY void Dispatch() {
5134 if (mEventMessage == eMouseEnter || mEventMessage == ePointerEnter) {
5135 for (int32_t i = mTargets.Count() - 1; i >= 0; --i) {
5136 nsCOMPtr<nsIWidget> widget = mESM->DispatchMouseOrPointerBoundaryEvent(
5137 mMouseEvent, mEventMessage, MOZ_KnownLive(mTargets[i])(mTargets[i]),
5138 mRelatedTarget);
5139 }
5140 } else {
5141 for (int32_t i = 0; i < mTargets.Count(); ++i) {
5142 nsCOMPtr<nsIWidget> widget = mESM->DispatchMouseOrPointerBoundaryEvent(
5143 mMouseEvent, mEventMessage, MOZ_KnownLive(mTargets[i])(mTargets[i]),
5144 mRelatedTarget);
5145 }
5146 }
5147 }
5148
5149 // Nothing overwrites anything after constructor. Please remove MOZ_KnownLive
5150 // and MOZ_KNOWN_LIVE if anything marked as such becomes mutable.
5151 const RefPtr<EventStateManager> mESM;
5152 nsCOMArray<nsIContent> mTargets;
5153 MOZ_KNOWN_LIVE nsCOMPtr<nsIContent> mRelatedTarget;
5154 WidgetMouseEvent* mMouseEvent;
5155 EventMessage mEventMessage;
5156};
5157
5158void EventStateManager::NotifyMouseOut(WidgetMouseEvent* aMouseEvent,
5159 nsIContent* aMovingInto) {
5160 const bool isPointer = aMouseEvent->mClass == ePointerEventClass;
5161 LogModule* const logModule =
5162 isPointer ? sPointerBoundaryLog : sMouseBoundaryLog;
5163
5164 RefPtr<OverOutElementsWrapper> wrapper = GetWrapperByEventID(aMouseEvent);
5165
5166 // If there is no deepest "leave" event target, that means the last "over"
5167 // target has already been removed from the tree. Therefore, checking only
5168 // the "leave" event target is enough.
5169 if (!wrapper || !wrapper->GetDeepestLeaveEventTarget()) {
5170 return;
5171 }
5172 // Before firing "out" and/or "leave" events, check for recursion
5173 if (wrapper->IsDispatchingOutEventOnLastOverEventTarget()) {
5174 return;
5175 }
5176
5177 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOut: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5178 ("NotifyMouseOut: the source event is %s (IsReal()=%s)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOut: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5179 ToChar(aMouseEvent->mMessage),do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOut: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5180 aMouseEvent->IsReal() ? "true" : "false"))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOut: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
;
5181
5182 // XXX If a content node is a container of remove content, it should be
5183 // replaced with them and its children should not be visible. Therefore,
5184 // if the deepest "enter" target is not the last "over" target, i.e., the
5185 // last "over" target has been removed from the DOM tree, it means that the
5186 // child/descendant was not replaced by remote content. So,
5187 // wrapper->GetOutEventTaget() may be enough here.
5188 if (RefPtr<nsFrameLoaderOwner> flo =
5189 do_QueryObject(wrapper->GetDeepestLeaveEventTarget())) {
5190 if (BrowsingContext* bc = flo->GetExtantBrowsingContext()) {
5191 if (nsIDocShell* docshell = bc->GetDocShell()) {
5192 if (RefPtr<nsPresContext> presContext = docshell->GetPresContext()) {
5193 EventStateManager* kidESM = presContext->EventStateManager();
5194 // Not moving into any element in this subdocument
5195 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying child EventStateManager (%p) of \"out\" "
"event...", kidESM); } } while (0)
5196 ("Notifying child EventStateManager (%p) of \"out\" "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying child EventStateManager (%p) of \"out\" "
"event...", kidESM); } } while (0)
5197 "event...",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying child EventStateManager (%p) of \"out\" "
"event...", kidESM); } } while (0)
5198 kidESM))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying child EventStateManager (%p) of \"out\" "
"event...", kidESM); } } while (0)
;
5199 kidESM->NotifyMouseOut(aMouseEvent, nullptr);
5200 }
5201 }
5202 }
5203 }
5204 // That could have caused DOM events which could wreak havoc. Reverify
5205 // things and be careful.
5206 if (!wrapper->GetDeepestLeaveEventTarget()) {
5207 return;
5208 }
5209
5210 wrapper->WillDispatchOutAndOrLeaveEvent();
5211
5212 // Don't touch hover state if aMovingInto is non-null. Caller will update
5213 // hover state itself, and we have optimizations for hover switching between
5214 // two nearby elements both deep in the DOM tree that would be defeated by
5215 // switching the hover state to null here.
5216 if (!aMovingInto && !isPointer) {
5217 // Unset :hover
5218 SetContentState(nullptr, ElementState::HOVER);
5219 }
5220
5221 EnterLeaveDispatcher leaveDispatcher(
5222 this, wrapper->GetDeepestLeaveEventTarget(), aMovingInto, aMouseEvent,
5223 isPointer ? ePointerLeave : eMouseLeave);
5224
5225 // "out" events hould be fired only when the deepest "leave" event target
5226 // is the last "over" event target.
5227 if (nsCOMPtr<nsIContent> outEventTarget = wrapper->GetOutEventTarget()) {
5228 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
5229 ("Dispatching %s event to %s (%p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
5230 isPointer ? "ePointerOut" : "eMouseOut",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
5231 outEventTarget ? ToString(*outEventTarget).c_str() : "nullptr",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
5232 outEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
;
5233 nsCOMPtr<nsIWidget> widget = DispatchMouseOrPointerBoundaryEvent(
5234 aMouseEvent, isPointer ? ePointerOut : eMouseOut, outEventTarget,
5235 aMovingInto);
5236 }
5237
5238 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5239 ("Dispatching %s event to %s (%p) and its ancestors",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5240 isPointer ? "ePointerLeave" : "eMouseLeave",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5241 wrapper->GetDeepestLeaveEventTarget()do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5242 ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str()do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5243 : "nullptr",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5244 wrapper->GetDeepestLeaveEventTarget()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
;
5245 leaveDispatcher.Dispatch();
5246
5247 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"out\" and/or \"leave\" events"
); } } while (0)
5248 ("Dispatched \"out\" and/or \"leave\" events"))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"out\" and/or \"leave\" events"
); } } while (0)
;
5249 wrapper->DidDispatchOutAndOrLeaveEvent();
5250}
5251
5252void EventStateManager::RecomputeMouseEnterStateForRemoteFrame(
5253 Element& aElement) {
5254 if (!mMouseEnterLeaveHelper ||
5255 mMouseEnterLeaveHelper->GetDeepestLeaveEventTarget() != &aElement) {
5256 return;
5257 }
5258
5259 if (BrowserParent* remote = BrowserParent::GetFrom(&aElement)) {
5260 remote->MouseEnterIntoWidget();
5261 }
5262}
5263
5264void EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
5265 nsIContent* aContent) {
5266 NS_ASSERTION(aContent, "Mouse must be over something")do { if (!(aContent)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Mouse must be over something"
, "aContent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5266); MOZ_PretendNoReturn(); } } while (0)
;
5267
5268 const bool isPointer = aMouseEvent->mClass == ePointerEventClass;
5269 LogModule* const logModule =
5270 isPointer ? sPointerBoundaryLog : sMouseBoundaryLog;
5271
5272 RefPtr<OverOutElementsWrapper> wrapper = GetWrapperByEventID(aMouseEvent);
5273
5274 // If we have next "out" event target and it's the new "over" target, we don't
5275 // need to dispatch "out" nor "enter" event.
5276 if (!wrapper || aContent == wrapper->GetOutEventTarget()) {
5277 return;
5278 }
5279
5280 // Before firing "over" and "enter" events, check for recursion
5281 if (wrapper->IsDispatchingOverEventOn(aContent)) {
5282 return;
5283 }
5284
5285 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOver: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5286 ("NotifyMouseOver: the source event is %s (IsReal()=%s)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOver: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5287 ToChar(aMouseEvent->mMessage),do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOver: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5288 aMouseEvent->IsReal() ? "true" : "false"))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOver: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
;
5289
5290 // Check to see if we're a subdocument and if so update the parent
5291 // document's ESM state to indicate that the mouse is over the
5292 // content associated with our subdocument.
5293 EnsureDocument(mPresContext);
5294 if (Document* parentDoc = mDocument->GetInProcessParentDocument()) {
5295 if (nsCOMPtr<nsIContent> docContent = mDocument->GetEmbedderElement()) {
5296 if (PresShell* parentPresShell = parentDoc->GetPresShell()) {
5297 RefPtr<EventStateManager> parentESM =
5298 parentPresShell->GetPresContext()->EventStateManager();
5299 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying parent EventStateManager (%p) of \"over\" "
"event...", parentESM.get()); } } while (0)
5300 ("Notifying parent EventStateManager (%p) of \"over\" "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying parent EventStateManager (%p) of \"over\" "
"event...", parentESM.get()); } } while (0)
5301 "event...",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying parent EventStateManager (%p) of \"over\" "
"event...", parentESM.get()); } } while (0)
5302 parentESM.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying parent EventStateManager (%p) of \"over\" "
"event...", parentESM.get()); } } while (0)
;
5303 parentESM->NotifyMouseOver(aMouseEvent, docContent);
5304 }
5305 }
5306 }
5307 // Firing the DOM event in the parent document could cause all kinds
5308 // of havoc. Reverify and take care.
5309 if (aContent == wrapper->GetOutEventTarget()) {
5310 return;
5311 }
5312
5313 // Remember the deepest leave event target as the related content for the
5314 // DispatchMouseOrPointerBoundaryEvent() call below, since NotifyMouseOut()
5315 // resets it, bug 298477.
5316 nsCOMPtr<nsIContent> deepestLeaveEventTarget =
5317 wrapper->GetDeepestLeaveEventTarget();
5318
5319 EnterLeaveDispatcher enterDispatcher(this, aContent, deepestLeaveEventTarget,
5320 aMouseEvent,
5321 isPointer ? ePointerEnter : eMouseEnter);
5322
5323 if (!isPointer) {
5324 SetContentState(aContent, ElementState::HOVER);
5325 }
5326
5327 NotifyMouseOut(aMouseEvent, aContent);
5328
5329 wrapper->WillDispatchOverAndEnterEvent(aContent);
5330
5331 // Fire mouseover
5332 // XXX If aContent has already been removed from the DOM tree, what should we
5333 // do? At least, dispatching `mouseover` on it is odd.
5334 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOver" : "eMoustOver", aContent ? ToString(*aContent
).c_str() : "nullptr", aContent); } } while (0)
5335 ("Dispatching %s event to %s (%p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOver" : "eMoustOver", aContent ? ToString(*aContent
).c_str() : "nullptr", aContent); } } while (0)
5336 isPointer ? "ePointerOver" : "eMoustOver",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOver" : "eMoustOver", aContent ? ToString(*aContent
).c_str() : "nullptr", aContent); } } while (0)
5337 aContent ? ToString(*aContent).c_str() : "nullptr", aContent))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOver" : "eMoustOver", aContent ? ToString(*aContent
).c_str() : "nullptr", aContent); } } while (0)
;
5338 nsCOMPtr<nsIWidget> targetWidget = DispatchMouseOrPointerBoundaryEvent(
5339 aMouseEvent, isPointer ? ePointerOver : eMouseOver, aContent,
5340 deepestLeaveEventTarget);
5341
5342 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerEnter" : "eMouseEnter", aContent ? ToString
(*aContent).c_str() : "nullptr", aContent); } } while (0)
5343 ("Dispatching %s event to %s (%p) and its ancestors",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerEnter" : "eMouseEnter", aContent ? ToString
(*aContent).c_str() : "nullptr", aContent); } } while (0)
5344 isPointer ? "ePointerEnter" : "eMouseEnter",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerEnter" : "eMouseEnter", aContent ? ToString
(*aContent).c_str() : "nullptr", aContent); } } while (0)
5345 aContent ? ToString(*aContent).c_str() : "nullptr", aContent))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerEnter" : "eMouseEnter", aContent ? ToString
(*aContent).c_str() : "nullptr", aContent); } } while (0)
;
5346 enterDispatcher.Dispatch();
5347
5348 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"over\" and \"enter\" events (the original \"over\" "
"event target was in the document %p, and now in %p)", aContent
->GetComposedDoc(), mDocument.get()); } } while (0)
5349 ("Dispatched \"over\" and \"enter\" events (the original \"over\" "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"over\" and \"enter\" events (the original \"over\" "
"event target was in the document %p, and now in %p)", aContent
->GetComposedDoc(), mDocument.get()); } } while (0)
5350 "event target was in the document %p, and now in %p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"over\" and \"enter\" events (the original \"over\" "
"event target was in the document %p, and now in %p)", aContent
->GetComposedDoc(), mDocument.get()); } } while (0)
5351 aContent->GetComposedDoc(), mDocument.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"over\" and \"enter\" events (the original \"over\" "
"event target was in the document %p, and now in %p)", aContent
->GetComposedDoc(), mDocument.get()); } } while (0)
;
5352 wrapper->DidDispatchOverAndEnterEvent(
5353 aContent->GetComposedDoc() == mDocument ? aContent : nullptr,
5354 targetWidget);
5355}
5356
5357// Returns the center point of the window's client area. This is
5358// in widget coordinates, i.e. relative to the widget's top-left
5359// corner, not in screen coordinates, the same units that UIEvent::
5360// refpoint is in. It may not be the exact center of the window if
5361// the platform requires rounding the coordinate.
5362static LayoutDeviceIntPoint GetWindowClientRectCenter(nsIWidget* aWidget) {
5363 NS_ENSURE_TRUE(aWidget, LayoutDeviceIntPoint(0, 0))do { if ((__builtin_expect(!!(!(aWidget)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aWidget" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5363); return LayoutDeviceIntPoint(0, 0); } } while (false)
;
5364
5365 LayoutDeviceIntRect rect = aWidget->GetClientBounds();
5366 LayoutDeviceIntPoint point(rect.width / 2, rect.height / 2);
5367 int32_t round = aWidget->RoundsWidgetCoordinatesTo();
5368 point.x = point.x / round * round;
5369 point.y = point.y / round * round;
5370 return point;
5371}
5372
5373void EventStateManager::GeneratePointerEnterExit(EventMessage aMessage,
5374 WidgetMouseEvent* aEvent) {
5375 WidgetPointerEvent pointerEvent(*aEvent);
5376 pointerEvent.mMessage = aMessage;
5377 GenerateMouseEnterExit(&pointerEvent);
5378}
5379
5380/* static */
5381void EventStateManager::UpdateLastRefPointOfMouseEvent(
5382 WidgetMouseEvent* aMouseEvent) {
5383 if (aMouseEvent->mMessage != eMouseMove &&
5384 aMouseEvent->mMessage != ePointerMove) {
5385 return;
5386 }
5387
5388 // Mouse movement is reported on the MouseEvent.movement{X,Y} fields.
5389 // Movement is calculated in UIEvent::GetMovementPoint() as:
5390 // previous_mousemove_mRefPoint - current_mousemove_mRefPoint.
5391 if (PointerLockManager::IsLocked() && aMouseEvent->mWidget) {
5392 // The pointer is locked. If the pointer is not located at the center of
5393 // the window, dispatch a synthetic mousemove to return the pointer there.
5394 // Doing this between "real" pointer moves gives the impression that the
5395 // (locked) pointer can continue moving and won't stop at the screen
5396 // boundary. We cancel the synthetic event so that we don't end up
5397 // dispatching the centering move event to content.
5398 aMouseEvent->mLastRefPoint =
5399 GetWindowClientRectCenter(aMouseEvent->mWidget);
5400
5401 } else if (sLastRefPoint == kInvalidRefPoint) {
5402 // We don't have a valid previous mousemove mRefPoint. This is either
5403 // the first move we've encountered, or the mouse has just re-entered
5404 // the application window. We should report (0,0) movement for this
5405 // case, so make the current and previous mRefPoints the same.
5406 aMouseEvent->mLastRefPoint = aMouseEvent->mRefPoint;
5407 } else {
5408 aMouseEvent->mLastRefPoint = sLastRefPoint;
5409 }
5410}
5411
5412/* static */
5413void EventStateManager::ResetPointerToWindowCenterWhilePointerLocked(
5414 WidgetMouseEvent* aMouseEvent) {
5415 MOZ_ASSERT(PointerLockManager::IsLocked())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(PointerLockManager::IsLocked())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(PointerLockManager::IsLocked
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("PointerLockManager::IsLocked()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5415); AnnotateMozCrashReason("MOZ_ASSERT" "(" "PointerLockManager::IsLocked()"
")"); do { *((volatile int*)__null) = 5415; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5416 if ((aMouseEvent->mMessage != eMouseMove &&
5417 aMouseEvent->mMessage != ePointerMove) ||
5418 !aMouseEvent->mWidget) {
5419 return;
5420 }
5421
5422 // We generate pointermove from mousemove event, so only synthesize native
5423 // mouse move and update sSynthCenteringPoint by mousemove event.
5424 bool updateSynthCenteringPoint = aMouseEvent->mMessage == eMouseMove;
5425
5426 // The pointer is locked. If the pointer is not located at the center of
5427 // the window, dispatch a synthetic mousemove to return the pointer there.
5428 // Doing this between "real" pointer moves gives the impression that the
5429 // (locked) pointer can continue moving and won't stop at the screen
5430 // boundary. We cancel the synthetic event so that we don't end up
5431 // dispatching the centering move event to content.
5432 LayoutDeviceIntPoint center = GetWindowClientRectCenter(aMouseEvent->mWidget);
5433
5434 if (aMouseEvent->mRefPoint != center && updateSynthCenteringPoint) {
5435 // Mouse move doesn't finish at the center of the window. Dispatch a
5436 // synthetic native mouse event to move the pointer back to the center
5437 // of the window, to faciliate more movement. But first, record that
5438 // we've dispatched a synthetic mouse movement, so we can cancel it
5439 // in the other branch here.
5440 sSynthCenteringPoint = center;
5441 // XXX Once we fix XXX comments in SetPointerLock about this API, we could
5442 // restrict that this API works only in the automation mode or in the
5443 // pointer locked situation.
5444 aMouseEvent->mWidget->SynthesizeNativeMouseMove(
5445 center + aMouseEvent->mWidget->WidgetToScreenOffset(), nullptr);
5446 } else if (aMouseEvent->mRefPoint == sSynthCenteringPoint) {
5447 // This is the "synthetic native" event we dispatched to re-center the
5448 // pointer. Cancel it so we don't expose the centering move to content.
5449 aMouseEvent->StopPropagation();
5450 // Clear sSynthCenteringPoint so we don't cancel other events
5451 // targeted at the center.
5452 if (updateSynthCenteringPoint) {
5453 sSynthCenteringPoint = kInvalidRefPoint;
5454 }
5455 }
5456}
5457
5458/* static */
5459void EventStateManager::UpdateLastPointerPosition(
5460 WidgetMouseEvent* aMouseEvent) {
5461 if (aMouseEvent->mMessage != eMouseMove) {
5462 return;
5463 }
5464 sLastRefPoint = aMouseEvent->mRefPoint;
5465}
5466
5467void EventStateManager::GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent) {
5468 EnsureDocument(mPresContext);
5469 if (!mDocument) return;
5470
5471 // Hold onto old target content through the event and reset after.
5472 nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
5473
5474 switch (aMouseEvent->mMessage) {
5475 case eMouseMove:
5476 case ePointerMove:
5477 case ePointerDown:
5478 case ePointerGotCapture: {
5479 // Get the target content target (mousemove target == mouseover target)
5480 nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
5481 if (!targetElement) {
5482 // We're always over the document root, even if we're only
5483 // over dead space in a page (whose frame is not associated with
5484 // any content) or in print preview dead space
5485 targetElement = mDocument->GetRootElement();
5486 }
5487 if (targetElement) {
5488 NotifyMouseOver(aMouseEvent, targetElement);
5489 }
5490 break;
5491 }
5492 case ePointerUp: {
5493 if (!StaticPrefs::
5494 dom_events_mouse_pointer_boundary_keep_enter_targets_after_over_target_removed()) {
5495 // In the legacy mode, we should do nothing if the event has not been
5496 // dispatched yet (i.e., called by PreHandleEvent).
5497 // On the other hand, if the event was dispatched (i.e., called by
5498 // PostEventHandler), we need to dispatch "pointerout" and
5499 // "pointerleave" events because the pointer will be removed
5500 // (invalidated) by the "pointerup" operation.
5501 if (!aMouseEvent->mFlags.mDispatchedAtLeastOnce) {
5502 break;
5503 }
5504 MOZ_ASSERT(!aMouseEvent->InputSourceSupportsHover())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aMouseEvent->InputSourceSupportsHover())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aMouseEvent->InputSourceSupportsHover()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aMouseEvent->InputSourceSupportsHover()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5504); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aMouseEvent->InputSourceSupportsHover()"
")"); do { *((volatile int*)__null) = 5504; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5505 // Get the target content target (pointermove target == pointerover
5506 // target)
5507 nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
5508 if (!targetElement) {
5509 // We're always over the document root, even if we're only
5510 // over dead space in a page (whose frame is not associated with
5511 // any content) or in print preview dead space
5512 targetElement = mDocument->GetRootElement();
5513 }
5514 if (targetElement) {
5515 // XXX It's odd to override the `pointerout` event target with the
5516 // content under the pointer or something because it may have never
5517 // received `pointerover` event. I think that this was required for
5518 // digitizer which supports hover state (bug 985511). However, this
5519 // is now not called at ePointerUp if the device supports hover.
5520 RefPtr<OverOutElementsWrapper> helper =
5521 GetWrapperByEventID(aMouseEvent);
5522 if (helper) {
5523 helper->OverrideOverEventTarget(targetElement);
5524 }
5525 NotifyMouseOut(aMouseEvent, nullptr);
5526 }
5527 break;
5528 }
5529
5530 if (aMouseEvent->mFlags.mDispatchedAtLeastOnce) {
5531 // If we've already dispatched the pointerup event caused by
5532 // non-hoverable input device like touch, we need to synthesize
5533 // pointerout and pointerleave events because the poiner is valid only
5534 // while it's "down".
5535 if (!aMouseEvent->InputSourceSupportsHover()) {
5536 NotifyMouseOut(aMouseEvent, nullptr);
5537 }
5538 break;
5539 }
5540
5541 // If we're going to dispatch the pointerup event and the element under
5542 // the pointer is changed from the previous pointer event dispatching, we
5543 // need to dispatch pointer boundary events. If the pointing device is
5544 // hoverable, we always need to do it. Otherwise, an element captures the
5545 // pointer by default. If so, we don't need the boundary events, but if
5546 // the capture has already been released, e.g., by the capturing element
5547 // is removed, we need to dispatch the pointer boundary event the same
5548 // way as with hoverable pointer.
5549 if (aMouseEvent->InputSourceSupportsHover() ||
5550 !PointerEventHandler::GetPointerCapturingElement(
5551 aMouseEvent->pointerId)) {
5552 nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
5553 if (!targetElement) {
5554 targetElement = mDocument->GetRootElement();
5555 }
5556 if (targetElement) {
5557 NotifyMouseOver(aMouseEvent, targetElement);
5558 }
5559 break;
5560 }
5561 break;
5562 }
5563 case ePointerLeave:
5564 case ePointerCancel:
5565 case eMouseExitFromWidget: {
5566 // This is actually the window mouse exit or pointer leave event. We're
5567 // not moving into any new element.
5568
5569 RefPtr<OverOutElementsWrapper> helper = GetWrapperByEventID(aMouseEvent);
5570 if (helper) {
5571 nsCOMPtr<nsIWidget> lastOverWidget = helper->GetLastOverWidget();
5572 if (lastOverWidget &&
5573 nsContentUtils::GetTopLevelWidget(aMouseEvent->mWidget) !=
5574 nsContentUtils::GetTopLevelWidget(lastOverWidget)) {
5575 // the Mouse/PointerOut event widget doesn't have same top widget with
5576 // the last over event target, it's a spurious event for the frame for
5577 // the target.
5578 break;
5579 }
5580 }
5581
5582 // Reset sLastRefPoint, so that we'll know not to report any
5583 // movement the next time we re-enter the window.
5584 sLastRefPoint = kInvalidRefPoint;
5585
5586 NotifyMouseOut(aMouseEvent, nullptr);
5587 break;
5588 }
5589 default:
5590 break;
5591 }
5592
5593 // reset mCurretTargetContent to what it was
5594 mCurrentTargetContent = targetBeforeEvent;
5595}
5596
5597OverOutElementsWrapper* EventStateManager::GetWrapperByEventID(
5598 WidgetMouseEvent* aEvent) {
5599 WidgetPointerEvent* pointer = aEvent->AsPointerEvent();
5600 if (!pointer) {
5601 MOZ_ASSERT(aEvent->AsMouseEvent() != nullptr)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->AsMouseEvent() != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->AsMouseEvent() !=
nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aEvent->AsMouseEvent() != nullptr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5601); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->AsMouseEvent() != nullptr"
")"); do { *((volatile int*)__null) = 5601; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5602 if (!mMouseEnterLeaveHelper) {
5603 mMouseEnterLeaveHelper = new OverOutElementsWrapper(
5604 OverOutElementsWrapper::BoundaryEventType::Mouse);
5605 }
5606 return mMouseEnterLeaveHelper;
5607 }
5608 return mPointersEnterLeaveHelper.GetOrInsertNew(
5609 pointer->pointerId, OverOutElementsWrapper::BoundaryEventType::Pointer);
5610}
5611
5612/* static */
5613void EventStateManager::SetPointerLock(nsIWidget* aWidget,
5614 nsPresContext* aPresContext) {
5615 // Reset mouse wheel transaction
5616 WheelTransaction::EndTransaction();
5617
5618 // Deal with DnD events
5619 nsCOMPtr<nsIDragService> dragService =
5620 do_GetService("@mozilla.org/widget/dragservice;1");
5621
5622 if (PointerLockManager::IsLocked()) {
5623 MOZ_ASSERT(aWidget, "Locking pointer requires a widget")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aWidget))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aWidget" " (" "Locking pointer requires a widget"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5623); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWidget" ") ("
"Locking pointer requires a widget" ")"); do { *((volatile int
*)__null) = 5623; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
5624 MOZ_ASSERT(aPresContext, "Locking pointer requires a presContext")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresContext))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPresContext" " ("
"Locking pointer requires a presContext" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5624); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresContext"
") (" "Locking pointer requires a presContext" ")"); do { *(
(volatile int*)__null) = 5624; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
5625
5626 // Release all pointer capture when a pointer lock is successfully applied
5627 // on an element.
5628 PointerEventHandler::ReleaseAllPointerCapture();
5629
5630 // Store the last known ref point so we can reposition the pointer after
5631 // unlock.
5632 sPreLockScreenPoint = LayoutDeviceIntPoint::Round(
5633 sLastScreenPoint * aPresContext->CSSToDevPixelScale());
5634
5635 // Fire a synthetic mouse move to ensure event state is updated. We first
5636 // set the mouse to the center of the window, so that the mouse event
5637 // doesn't report any movement.
5638 // XXX Cannot we do synthesize the native mousemove in the parent process
5639 // with calling LockNativePointer below? Then, we could make this API
5640 // work only in the automation mode.
5641 sLastRefPoint = GetWindowClientRectCenter(aWidget);
5642 aWidget->SynthesizeNativeMouseMove(
5643 sLastRefPoint + aWidget->WidgetToScreenOffset(), nullptr);
5644
5645 // Suppress DnD
5646 if (dragService) {
5647 dragService->Suppress();
5648 }
5649
5650 // Activate native pointer lock on platforms where it is required (Wayland)
5651 aWidget->LockNativePointer();
5652 } else {
5653 if (aWidget) {
5654 // Deactivate native pointer lock on platforms where it is required
5655 aWidget->UnlockNativePointer();
5656 }
5657
5658 // Reset SynthCenteringPoint to invalid so that next time we start
5659 // locking pointer, it has its initial value.
5660 sSynthCenteringPoint = kInvalidRefPoint;
5661 if (aWidget) {
5662 // Unlocking, so return pointer to the original position by firing a
5663 // synthetic mouse event. We first reset sLastRefPoint to its
5664 // pre-pointerlock position, so that the synthetic mouse event reports
5665 // no movement.
5666 sLastRefPoint = sPreLockScreenPoint - aWidget->WidgetToScreenOffset();
5667 // XXX Cannot we do synthesize the native mousemove in the parent process
5668 // with calling `UnlockNativePointer` above? Then, we could make this
5669 // API work only in the automation mode.
5670 aWidget->SynthesizeNativeMouseMove(sPreLockScreenPoint, nullptr);
5671 }
5672
5673 // Unsuppress DnD
5674 if (dragService) {
5675 dragService->Unsuppress();
5676 }
5677 }
5678}
5679
5680void EventStateManager::GenerateDragDropEnterExit(nsPresContext* aPresContext,
5681 WidgetDragEvent* aDragEvent) {
5682 // Hold onto old target content through the event and reset after.
5683 nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
5684
5685 switch (aDragEvent->mMessage) {
5686 case eDragOver: {
5687 // when dragging from one frame to another, events are fired in the
5688 // order: dragexit, dragenter, dragleave
5689 if (sLastDragOverFrame != mCurrentTarget) {
5690 // We'll need the content, too, to check if it changed separately from
5691 // the frames.
5692 nsCOMPtr<nsIContent> lastContent;
5693 nsCOMPtr<nsIContent> targetContent;
5694 mCurrentTarget->GetContentForEvent(aDragEvent,
5695 getter_AddRefs(targetContent));
5696 if (targetContent && targetContent->IsText()) {
5697 targetContent = targetContent->GetFlattenedTreeParent();
5698 }
5699
5700 if (sLastDragOverFrame) {
5701 // The frame has changed but the content may not have. Check before
5702 // dispatching to content
5703 sLastDragOverFrame->GetContentForEvent(aDragEvent,
5704 getter_AddRefs(lastContent));
5705 if (lastContent && lastContent->IsText()) {
5706 lastContent = lastContent->GetFlattenedTreeParent();
5707 }
5708
5709 RefPtr<nsPresContext> presContext = sLastDragOverFrame->PresContext();
5710 FireDragEnterOrExit(presContext, aDragEvent, eDragExit, targetContent,
5711 lastContent, sLastDragOverFrame);
5712 nsIContent* target = sLastDragOverFrame
5713 ? sLastDragOverFrame.GetFrame()->GetContent()
5714 : nullptr;
5715 // XXXedgar, look like we need to consider fission OOP iframe, too.
5716 if (IsTopLevelRemoteTarget(target)) {
5717 // Dragging something and moving from web content to chrome only
5718 // fires dragexit and dragleave to xul:browser. We have to forward
5719 // dragexit to sLastDragOverFrame when its content is a remote
5720 // target. We don't forward dragleave since it's generated from
5721 // dragexit.
5722 WidgetDragEvent remoteEvent(aDragEvent->IsTrusted(), eDragExit,
5723 aDragEvent->mWidget);
5724 remoteEvent.AssignDragEventData(*aDragEvent, true);
5725 remoteEvent.mFlags.mIsSynthesizedForTests =
5726 aDragEvent->mFlags.mIsSynthesizedForTests;
5727 nsEventStatus remoteStatus = nsEventStatus_eIgnore;
5728 HandleCrossProcessEvent(&remoteEvent, &remoteStatus);
5729 }
5730 }
5731
5732 AutoWeakFrame currentTraget = mCurrentTarget;
5733 FireDragEnterOrExit(aPresContext, aDragEvent, eDragEnter, lastContent,
5734 targetContent, currentTraget);
5735
5736 if (sLastDragOverFrame) {
5737 RefPtr<nsPresContext> presContext = sLastDragOverFrame->PresContext();
5738 FireDragEnterOrExit(presContext, aDragEvent, eDragLeave,
5739 targetContent, lastContent, sLastDragOverFrame);
5740 }
5741
5742 sLastDragOverFrame = mCurrentTarget;
5743 }
5744 } break;
5745
5746 case eDragExit: {
5747 // This is actually the window mouse exit event.
5748 if (sLastDragOverFrame) {
5749 nsCOMPtr<nsIContent> lastContent;
5750 sLastDragOverFrame->GetContentForEvent(aDragEvent,
5751 getter_AddRefs(lastContent));
5752
5753 RefPtr<nsPresContext> lastDragOverFramePresContext =
5754 sLastDragOverFrame->PresContext();
5755 FireDragEnterOrExit(lastDragOverFramePresContext, aDragEvent, eDragExit,
5756 nullptr, lastContent, sLastDragOverFrame);
5757 FireDragEnterOrExit(lastDragOverFramePresContext, aDragEvent,
5758 eDragLeave, nullptr, lastContent,
5759 sLastDragOverFrame);
5760
5761 sLastDragOverFrame = nullptr;
5762 }
5763 } break;
5764
5765 default:
5766 break;
5767 }
5768
5769 // reset mCurretTargetContent to what it was
5770 mCurrentTargetContent = targetBeforeEvent;
5771
5772 // Now flush all pending notifications, for better responsiveness.
5773 FlushLayout(aPresContext);
5774}
5775
5776void EventStateManager::FireDragEnterOrExit(nsPresContext* aPresContext,
5777 WidgetDragEvent* aDragEvent,
5778 EventMessage aMessage,
5779 nsIContent* aRelatedTarget,
5780 nsIContent* aTargetContent,
5781 AutoWeakFrame& aTargetFrame) {
5782 MOZ_ASSERT(aMessage == eDragLeave || aMessage == eDragExit ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eDragLeave || aMessage == eDragExit || aMessage
== eDragEnter)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aMessage == eDragLeave || aMessage
== eDragExit || aMessage == eDragEnter))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eDragLeave || aMessage == eDragExit || aMessage == eDragEnter"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5783); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eDragLeave || aMessage == eDragExit || aMessage == eDragEnter"
")"); do { *((volatile int*)__null) = 5783; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5783 aMessage == eDragEnter)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eDragLeave || aMessage == eDragExit || aMessage
== eDragEnter)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aMessage == eDragLeave || aMessage
== eDragExit || aMessage == eDragEnter))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eDragLeave || aMessage == eDragExit || aMessage == eDragEnter"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5783); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eDragLeave || aMessage == eDragExit || aMessage == eDragEnter"
")"); do { *((volatile int*)__null) = 5783; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5784 nsEventStatus status = nsEventStatus_eIgnore;
5785 WidgetDragEvent event(aDragEvent->IsTrusted(), aMessage, aDragEvent->mWidget);
5786 event.AssignDragEventData(*aDragEvent, false);
5787 event.mFlags.mIsSynthesizedForTests =
5788 aDragEvent->mFlags.mIsSynthesizedForTests;
5789 event.mRelatedTarget = aRelatedTarget;
5790 if (aMessage == eDragExit && !StaticPrefs::dom_event_dragexit_enabled()) {
5791 event.mFlags.mOnlyChromeDispatch = true;
5792 }
5793
5794 mCurrentTargetContent = aTargetContent;
5795
5796 if (aTargetContent != aRelatedTarget) {
5797 // XXX This event should still go somewhere!!
5798 if (aTargetContent) {
5799 EventDispatcher::Dispatch(aTargetContent, aPresContext, &event, nullptr,
5800 &status);
5801 }
5802
5803 // adjust the drag hover if the dragenter event was cancelled or this is a
5804 // drag exit
5805 if (status == nsEventStatus_eConsumeNoDefault || aMessage == eDragExit) {
5806 SetContentState((aMessage == eDragEnter) ? aTargetContent : nullptr,
5807 ElementState::DRAGOVER);
5808 }
5809
5810 // collect any changes to moz cursor settings stored in the event's
5811 // data transfer.
5812 UpdateDragDataTransfer(&event);
5813 }
5814
5815 // Finally dispatch the event to the frame
5816 if (aTargetFrame) {
5817 aTargetFrame->HandleEvent(aPresContext, &event, &status);
5818 }
5819}
5820
5821void EventStateManager::UpdateDragDataTransfer(WidgetDragEvent* dragEvent) {
5822 NS_ASSERTION(dragEvent, "drag event is null in UpdateDragDataTransfer!")do { if (!(dragEvent)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "drag event is null in UpdateDragDataTransfer!"
, "dragEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5822); MOZ_PretendNoReturn(); } } while (0)
;
5823 if (!dragEvent->mDataTransfer) {
5824 return;
5825 }
5826
5827 nsCOMPtr<nsIDragSession> dragSession =
5828 nsContentUtils::GetDragSession(mPresContext);
5829
5830 if (dragSession) {
5831 // the initial dataTransfer is the one from the dragstart event that
5832 // was set on the dragSession when the drag began.
5833 RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer();
5834 if (initialDataTransfer) {
5835 // retrieve the current moz cursor setting and save it.
5836 nsAutoString mozCursor;
5837 dragEvent->mDataTransfer->GetMozCursor(mozCursor);
5838 initialDataTransfer->SetMozCursor(mozCursor);
5839 }
5840 }
5841}
5842
5843nsresult EventStateManager::SetClickCount(WidgetMouseEvent* aEvent,
5844 nsEventStatus* aStatus,
5845 nsIContent* aOverrideClickTarget) {
5846 nsCOMPtr<nsIContent> mouseContent = aOverrideClickTarget;
5847 if (!mouseContent && mCurrentTarget) {
5848 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(mouseContent));
5849 }
5850 if (mouseContent && mouseContent->IsText()) {
5851 nsINode* parent = mouseContent->GetFlattenedTreeParentNode();
5852 if (parent && parent->IsContent()) {
5853 mouseContent = parent->AsContent();
5854 }
5855 }
5856
5857 LastMouseDownInfo& mouseDownInfo = GetLastMouseDownInfo(aEvent->mButton);
5858 if (aEvent->mMessage == eMouseDown) {
5859 mouseDownInfo.mLastMouseDownContent =
5860 !aEvent->mClickEventPrevented ? mouseContent : nullptr;
5861
5862 if (mouseDownInfo.mLastMouseDownContent) {
5863 if (HTMLInputElement* input = HTMLInputElement::FromNodeOrNull(
5864 mouseDownInfo.mLastMouseDownContent)) {
5865 mouseDownInfo.mLastMouseDownInputControlType =
5866 Some(input->ControlType());
5867 } else if (mouseDownInfo.mLastMouseDownContent
5868 ->IsInNativeAnonymousSubtree()) {
5869 if (HTMLInputElement* input = HTMLInputElement::FromNodeOrNull(
5870 mouseDownInfo.mLastMouseDownContent
5871 ->GetFlattenedTreeParent())) {
5872 mouseDownInfo.mLastMouseDownInputControlType =
5873 Some(input->ControlType());
5874 }
5875 }
5876 }
5877 } else {
5878 aEvent->mClickTarget =
5879 !aEvent->mClickEventPrevented
5880 ? GetCommonAncestorForMouseUp(
5881 mouseContent, mouseDownInfo.mLastMouseDownContent,
5882 mouseDownInfo.mLastMouseDownInputControlType)
5883 : nullptr;
5884 if (aEvent->mClickTarget) {
5885 aEvent->mClickCount = mouseDownInfo.mClickCount;
5886 mouseDownInfo.mClickCount = 0;
5887 } else {
5888 aEvent->mClickCount = 0;
5889 }
5890 mouseDownInfo.mLastMouseDownContent = nullptr;
5891 mouseDownInfo.mLastMouseDownInputControlType = Nothing();
5892 }
5893
5894 return NS_OK;
5895}
5896
5897// static
5898bool EventStateManager::EventCausesClickEvents(
5899 const WidgetMouseEvent& aMouseEvent) {
5900 if (NS_WARN_IF(aMouseEvent.mMessage != eMouseUp)NS_warn_if_impl(aMouseEvent.mMessage != eMouseUp, "aMouseEvent.mMessage != eMouseUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5900)
) {
5901 return false;
5902 }
5903 // If the mouseup event is synthesized event, we don't need to dispatch
5904 // click events.
5905 if (!aMouseEvent.IsReal()) {
5906 return false;
5907 }
5908 // If mouse is still over same element, clickcount will be > 1.
5909 // If it has moved it will be zero, so no click.
5910 if (!aMouseEvent.mClickCount || !aMouseEvent.mClickTarget) {
5911 return false;
5912 }
5913 // If click event was explicitly prevented, we shouldn't dispatch it.
5914 if (aMouseEvent.mClickEventPrevented) {
5915 return false;
5916 }
5917 // Check that the window isn't disabled before firing a click
5918 // (see bug 366544).
5919 return !(aMouseEvent.mWidget && !aMouseEvent.mWidget->IsEnabled());
5920}
5921
5922nsresult EventStateManager::InitAndDispatchClickEvent(
5923 WidgetMouseEvent* aMouseUpEvent, nsEventStatus* aStatus,
5924 EventMessage aMessage, PresShell* aPresShell, nsIContent* aMouseUpContent,
5925 AutoWeakFrame aCurrentTarget, bool aNoContentDispatch,
5926 nsIContent* aOverrideClickTarget) {
5927 MOZ_ASSERT(aMouseUpEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseUpEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseUpEvent))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aMouseUpEvent",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5927); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpEvent"
")"); do { *((volatile int*)__null) = 5927; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5928 MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(EventCausesClickEvents(*aMouseUpEvent))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(EventCausesClickEvents(*aMouseUpEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("EventCausesClickEvents(*aMouseUpEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5928); AnnotateMozCrashReason("MOZ_ASSERT" "(" "EventCausesClickEvents(*aMouseUpEvent)"
")"); do { *((volatile int*)__null) = 5928; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5929 MOZ_ASSERT(aMouseUpContent || aCurrentTarget || aOverrideClickTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseUpContent || aCurrentTarget || aOverrideClickTarget
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aMouseUpContent || aCurrentTarget || aOverrideClickTarget
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aMouseUpContent || aCurrentTarget || aOverrideClickTarget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5929); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpContent || aCurrentTarget || aOverrideClickTarget"
")"); do { *((volatile int*)__null) = 5929; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5930
5931 Maybe<WidgetPointerEvent> pointerEvent;
5932 Maybe<WidgetMouseEvent> mouseEvent;
5933 if (IsPointerEventMessage(aMessage)) {
5934 pointerEvent.emplace(aMouseUpEvent->IsTrusted(), aMessage,
5935 aMouseUpEvent->mWidget);
5936 } else {
5937 mouseEvent.emplace(aMouseUpEvent->IsTrusted(), aMessage,
5938 aMouseUpEvent->mWidget, WidgetMouseEvent::eReal);
5939 }
5940
5941 WidgetMouseEvent& mouseOrPointerEvent =
5942 pointerEvent.isSome() ? pointerEvent.ref() : mouseEvent.ref();
5943
5944 mouseOrPointerEvent.mRefPoint = aMouseUpEvent->mRefPoint;
5945 mouseOrPointerEvent.mClickCount = aMouseUpEvent->mClickCount;
5946 mouseOrPointerEvent.mModifiers = aMouseUpEvent->mModifiers;
5947 mouseOrPointerEvent.mButtons = aMouseUpEvent->mButtons;
5948 mouseOrPointerEvent.mTimeStamp = aMouseUpEvent->mTimeStamp;
5949 mouseOrPointerEvent.mFlags.mOnlyChromeDispatch = aNoContentDispatch;
5950 mouseOrPointerEvent.mFlags.mNoContentDispatch = aNoContentDispatch;
5951 mouseOrPointerEvent.mButton = aMouseUpEvent->mButton;
5952 mouseOrPointerEvent.pointerId = aMouseUpEvent->pointerId;
5953 mouseOrPointerEvent.mInputSource = aMouseUpEvent->mInputSource;
5954 nsIContent* target = aMouseUpContent;
5955 nsIFrame* targetFrame = aCurrentTarget;
5956 if (aOverrideClickTarget) {
5957 target = aOverrideClickTarget;
5958 targetFrame = aOverrideClickTarget->GetPrimaryFrame();
5959 }
5960
5961 if (!target->IsInComposedDoc()) {
5962 return NS_OK;
5963 }
5964
5965 // Use local event status for each click event dispatching since it'll be
5966 // cleared by EventStateManager::PreHandleEvent(). Therefore, dispatching
5967 // an event means that previous event status will be ignored.
5968 nsEventStatus status = nsEventStatus_eIgnore;
5969 nsresult rv = aPresShell->HandleEventWithTarget(
5970 &mouseOrPointerEvent, targetFrame, MOZ_KnownLive(target)(target), &status);
5971
5972 // Copy mMultipleActionsPrevented flag from a click event to the mouseup
5973 // event only when it's set to true. It may be set to true if an editor has
5974 // already handled it. This is important to avoid two or more default
5975 // actions handled here.
5976 aMouseUpEvent->mFlags.mMultipleActionsPrevented |=
5977 mouseOrPointerEvent.mFlags.mMultipleActionsPrevented;
5978 // If current status is nsEventStatus_eConsumeNoDefault, we don't need to
5979 // overwrite it.
5980 if (*aStatus == nsEventStatus_eConsumeNoDefault) {
5981 return rv;
5982 }
5983 // If new status is nsEventStatus_eConsumeNoDefault or
5984 // nsEventStatus_eConsumeDoDefault, use it.
5985 if (status == nsEventStatus_eConsumeNoDefault ||
5986 status == nsEventStatus_eConsumeDoDefault) {
5987 *aStatus = status;
5988 return rv;
5989 }
5990 // Otherwise, keep the original status.
5991 return rv;
5992}
5993
5994nsresult EventStateManager::PostHandleMouseUp(
5995 WidgetMouseEvent* aMouseUpEvent, nsEventStatus* aStatus,
5996 nsIContent* aOverrideClickTarget) {
5997 MOZ_ASSERT(aMouseUpEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseUpEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseUpEvent))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aMouseUpEvent",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5997); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpEvent"
")"); do { *((volatile int*)__null) = 5997; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5998 MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(EventCausesClickEvents(*aMouseUpEvent))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(EventCausesClickEvents(*aMouseUpEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("EventCausesClickEvents(*aMouseUpEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5998); AnnotateMozCrashReason("MOZ_ASSERT" "(" "EventCausesClickEvents(*aMouseUpEvent)"
")"); do { *((volatile int*)__null) = 5998; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5999 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5999); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 5999; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6000
6001 RefPtr<PresShell> presShell = mPresContext->GetPresShell();
6002 if (!presShell) {
6003 return NS_OK;
6004 }
6005
6006 nsCOMPtr<nsIContent> clickTarget =
6007 nsIContent::FromEventTargetOrNull(aMouseUpEvent->mClickTarget);
6008 NS_ENSURE_STATE(clickTarget)do { if ((__builtin_expect(!!(!(clickTarget)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "clickTarget" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6008); return NS_ERROR_UNEXPECTED; } } while (false)
;
6009
6010 // Fire click events if the event target is still available.
6011 // Note that do not include the eMouseUp event's status since we ignore it
6012 // for compatibility with the other browsers.
6013 nsEventStatus status = nsEventStatus_eIgnore;
6014 nsresult rv = DispatchClickEvents(presShell, aMouseUpEvent, &status,
6015 clickTarget, aOverrideClickTarget);
6016 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6016)
) {
6017 return rv;
6018 }
6019
6020 // Do not do anything if preceding click events are consumed.
6021 // Note that Chromium dispatches "paste" event and actually pates clipboard
6022 // text into focused editor even if the preceding click events are consumed.
6023 // However, this is different from our traditional behavior and does not
6024 // conform to DOM events. If we need to keep compatibility with Chromium,
6025 // we should change it later.
6026 if (status == nsEventStatus_eConsumeNoDefault) {
6027 *aStatus = nsEventStatus_eConsumeNoDefault;
6028 return NS_OK;
6029 }
6030
6031 // Handle middle click paste if it's enabled and the mouse button is middle.
6032 if (aMouseUpEvent->mButton != MouseButton::eMiddle ||
6033 !WidgetMouseEvent::IsMiddleClickPasteEnabled()) {
6034 return NS_OK;
6035 }
6036 DebugOnly<nsresult> rvIgnored =
6037 HandleMiddleClickPaste(presShell, aMouseUpEvent, &status, nullptr);
6038 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to paste for a middle click"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6039); } } while (false)
6039 "Failed to paste for a middle click")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to paste for a middle click"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6039); } } while (false)
;
6040
6041 // If new status is nsEventStatus_eConsumeNoDefault or
6042 // nsEventStatus_eConsumeDoDefault, use it.
6043 if (*aStatus != nsEventStatus_eConsumeNoDefault &&
6044 (status == nsEventStatus_eConsumeNoDefault ||
6045 status == nsEventStatus_eConsumeDoDefault)) {
6046 *aStatus = status;
6047 }
6048
6049 // Don't return error even if middle mouse paste fails since we haven't
6050 // handled it here.
6051 return NS_OK;
6052}
6053
6054nsresult EventStateManager::DispatchClickEvents(
6055 PresShell* aPresShell, WidgetMouseEvent* aMouseUpEvent,
6056 nsEventStatus* aStatus, nsIContent* aClickTarget,
6057 nsIContent* aOverrideClickTarget) {
6058 MOZ_ASSERT(aPresShell)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresShell)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresShell))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aPresShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6058); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresShell"
")"); do { *((volatile int*)__null) = 6058; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6059 MOZ_ASSERT(aMouseUpEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseUpEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseUpEvent))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aMouseUpEvent",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6059); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpEvent"
")"); do { *((volatile int*)__null) = 6059; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6060 MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(EventCausesClickEvents(*aMouseUpEvent))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(EventCausesClickEvents(*aMouseUpEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("EventCausesClickEvents(*aMouseUpEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6060); AnnotateMozCrashReason("MOZ_ASSERT" "(" "EventCausesClickEvents(*aMouseUpEvent)"
")"); do { *((volatile int*)__null) = 6060; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6061 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6061); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 6061; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6062 MOZ_ASSERT(aClickTarget || aOverrideClickTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aClickTarget || aOverrideClickTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aClickTarget || aOverrideClickTarget
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aClickTarget || aOverrideClickTarget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6062); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aClickTarget || aOverrideClickTarget"
")"); do { *((volatile int*)__null) = 6062; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6063
6064 bool notDispatchToContents =
6065 (aMouseUpEvent->mButton == MouseButton::eMiddle ||
6066 aMouseUpEvent->mButton == MouseButton::eSecondary);
6067
6068 bool fireAuxClick = notDispatchToContents;
6069
6070 AutoWeakFrame currentTarget = aClickTarget->GetPrimaryFrame();
6071 nsresult rv = InitAndDispatchClickEvent(
6072 aMouseUpEvent, aStatus, ePointerClick, aPresShell, aClickTarget,
6073 currentTarget, notDispatchToContents, aOverrideClickTarget);
6074 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6074)
) {
6075 return rv;
6076 }
6077
6078 // Fire auxclick event if necessary.
6079 if (fireAuxClick && *aStatus != nsEventStatus_eConsumeNoDefault &&
6080 aClickTarget && aClickTarget->IsInComposedDoc()) {
6081 rv = InitAndDispatchClickEvent(aMouseUpEvent, aStatus, ePointerAuxClick,
6082 aPresShell, aClickTarget, currentTarget,
6083 false, aOverrideClickTarget);
6084 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to dispatch ePointerAuxClick"
, "NS_SUCCEEDED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6085); } } while (false)
6085 "Failed to dispatch ePointerAuxClick")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to dispatch ePointerAuxClick"
, "NS_SUCCEEDED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6085); } } while (false)
;
6086 }
6087
6088 // Fire double click event if click count is 2.
6089 if (aMouseUpEvent->mClickCount == 2 && !fireAuxClick && aClickTarget &&
6090 aClickTarget->IsInComposedDoc()) {
6091 rv = InitAndDispatchClickEvent(aMouseUpEvent, aStatus, eMouseDoubleClick,
6092 aPresShell, aClickTarget, currentTarget,
6093 notDispatchToContents, aOverrideClickTarget);
6094 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6094)
) {
6095 return rv;
6096 }
6097 }
6098
6099 return rv;
6100}
6101
6102nsresult EventStateManager::HandleMiddleClickPaste(
6103 PresShell* aPresShell, WidgetMouseEvent* aMouseEvent,
6104 nsEventStatus* aStatus, EditorBase* aEditorBase) {
6105 MOZ_ASSERT(aPresShell)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresShell)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresShell))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aPresShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6105); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresShell"
")"); do { *((volatile int*)__null) = 6105; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6106 MOZ_ASSERT(aMouseEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseEvent))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aMouseEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6106); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseEvent"
")"); do { *((volatile int*)__null) = 6106; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6107 MOZ_ASSERT((aMouseEvent->mMessage == ePointerAuxClick &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aMouseEvent->mMessage == ePointerAuxClick &&
aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents
(*aMouseEvent))>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!((aMouseEvent->mMessage == ePointerAuxClick
&& aMouseEvent->mButton == MouseButton::eMiddle) ||
EventCausesClickEvents(*aMouseEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6109); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
")"); do { *((volatile int*)__null) = 6109; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6108 aMouseEvent->mButton == MouseButton::eMiddle) ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aMouseEvent->mMessage == ePointerAuxClick &&
aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents
(*aMouseEvent))>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!((aMouseEvent->mMessage == ePointerAuxClick
&& aMouseEvent->mButton == MouseButton::eMiddle) ||
EventCausesClickEvents(*aMouseEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6109); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
")"); do { *((volatile int*)__null) = 6109; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6109 EventCausesClickEvents(*aMouseEvent))do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aMouseEvent->mMessage == ePointerAuxClick &&
aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents
(*aMouseEvent))>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!((aMouseEvent->mMessage == ePointerAuxClick
&& aMouseEvent->mButton == MouseButton::eMiddle) ||
EventCausesClickEvents(*aMouseEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6109); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
")"); do { *((volatile int*)__null) = 6109; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6110 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6110); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 6110; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6111 MOZ_ASSERT(*aStatus != nsEventStatus_eConsumeNoDefault)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(*aStatus != nsEventStatus_eConsumeNoDefault))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6111); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault"
")"); do { *((volatile int*)__null) = 6111; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6112
6113 // Even if we're called twice or more for a mouse operation, we should
6114 // handle only once. Although mMultipleActionsPrevented may be set to
6115 // true by different event handler in the future, we can use it for now.
6116 if (aMouseEvent->mFlags.mMultipleActionsPrevented) {
6117 return NS_OK;
6118 }
6119 aMouseEvent->mFlags.mMultipleActionsPrevented = true;
6120
6121 RefPtr<Selection> selection;
6122 if (aEditorBase) {
6123 selection = aEditorBase->GetSelection();
6124 if (NS_WARN_IF(!selection)NS_warn_if_impl(!selection, "!selection", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6124)
) {
6125 return NS_ERROR_FAILURE;
6126 }
6127 } else {
6128 Document* document = aPresShell->GetDocument();
6129 if (NS_WARN_IF(!document)NS_warn_if_impl(!document, "!document", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6129)
) {
6130 return NS_ERROR_FAILURE;
6131 }
6132 selection = nsCopySupport::GetSelectionForCopy(document);
6133 if (NS_WARN_IF(!selection)NS_warn_if_impl(!selection, "!selection", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6133)
) {
6134 return NS_ERROR_FAILURE;
6135 }
6136
6137 const nsRange* range = selection->GetRangeAt(0);
6138 if (range) {
6139 nsINode* target = range->GetStartContainer();
6140 if (target && target->OwnerDoc()->IsInChromeDocShell()) {
6141 // In Chrome document, limit middle-click pasting to only the editor
6142 // because it looks odd if pasting works in the focused editor when you
6143 // middle-click toolbar or something which are far from the editor.
6144 // However, as DevTools especially Web Console module assumes that paste
6145 // event will be fired when middle-click even on not editor, don't limit
6146 // it.
6147 return NS_OK;
6148 }
6149 }
6150 }
6151
6152 // Don't modify selection here because we've already set caret to the point
6153 // at "mousedown" event.
6154
6155 nsIClipboard::ClipboardType clipboardType = nsIClipboard::kGlobalClipboard;
6156 nsCOMPtr<nsIClipboard> clipboardService =
6157 do_GetService("@mozilla.org/widget/clipboard;1");
6158 if (clipboardService && clipboardService->IsClipboardTypeSupported(
6159 nsIClipboard::kSelectionClipboard)) {
6160 clipboardType = nsIClipboard::kSelectionClipboard;
6161 }
6162
6163 // Fire ePaste event by ourselves since we need to dispatch "paste" event
6164 // even if the middle click event was consumed for compatibility with
6165 // Chromium.
6166 if (!nsCopySupport::FireClipboardEvent(ePaste, Some(clipboardType),
6167 aPresShell, selection)) {
6168 *aStatus = nsEventStatus_eConsumeNoDefault;
6169 return NS_OK;
6170 }
6171
6172 // Although we've fired "paste" event, there is no editor to accept the
6173 // clipboard content.
6174 if (!aEditorBase) {
6175 return NS_OK;
6176 }
6177
6178 // Check if the editor is still the good target to paste.
6179 if (aEditorBase->Destroyed() || aEditorBase->IsReadonly()) {
6180 // XXX Should we consume the event when the editor is readonly and/or
6181 // disabled?
6182 return NS_OK;
6183 }
6184
6185 // The selection may have been modified during reflow. Therefore, we
6186 // should adjust event target to pass IsAcceptableInputEvent().
6187 const nsRange* range = selection->GetRangeAt(0);
6188 if (!range) {
6189 return NS_OK;
6190 }
6191 WidgetMouseEvent mouseEvent(*aMouseEvent);
6192 mouseEvent.mOriginalTarget = range->GetStartContainer();
6193 if (NS_WARN_IF(!mouseEvent.mOriginalTarget)NS_warn_if_impl(!mouseEvent.mOriginalTarget, "!mouseEvent.mOriginalTarget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6193)
||
6194 !aEditorBase->IsAcceptableInputEvent(&mouseEvent)) {
6195 return NS_OK;
6196 }
6197
6198 // If Control key is pressed, we should paste clipboard content as
6199 // quotation. Otherwise, paste it as is.
6200 if (aMouseEvent->IsControl()) {
6201 DebugOnly<nsresult> rv = aEditorBase->PasteAsQuotationAsAction(
6202 clipboardType, EditorBase::DispatchPasteEvent::No);
6203 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to paste as quotation")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to paste as quotation"
, "NS_SUCCEEDED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6203); } } while (false)
;
6204 } else {
6205 DebugOnly<nsresult> rv = aEditorBase->PasteAsAction(
6206 clipboardType, EditorBase::DispatchPasteEvent::No);
6207 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to paste")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to paste", "NS_SUCCEEDED(rv)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6207); } } while (false)
;
6208 }
6209 *aStatus = nsEventStatus_eConsumeNoDefault;
6210
6211 return NS_OK;
6212}
6213
6214void EventStateManager::ConsumeInteractionData(
6215 Record<nsString, dom::InteractionData>& aInteractions) {
6216 OnTypingInteractionEnded();
6217
6218 aInteractions.Entries().Clear();
6219 auto newEntry = aInteractions.Entries().AppendElement();
6220 newEntry->mKey = u"Typing"_ns;
6221 newEntry->mValue = gTypingInteraction;
6222 gTypingInteraction = {};
6223}
6224
6225nsIFrame* EventStateManager::GetEventTarget() {
6226 PresShell* presShell;
6227 if (mCurrentTarget || !mPresContext ||
6228 !(presShell = mPresContext->GetPresShell())) {
6229 return mCurrentTarget;
6230 }
6231
6232 if (mCurrentTargetContent) {
6233 mCurrentTarget = mPresContext->GetPrimaryFrameFor(mCurrentTargetContent);
6234 if (mCurrentTarget) {
6235 return mCurrentTarget;
6236 }
6237 }
6238
6239 nsIFrame* frame = presShell->GetCurrentEventFrame();
6240 return (mCurrentTarget = frame);
6241}
6242
6243already_AddRefed<nsIContent> EventStateManager::GetEventTargetContent(
6244 WidgetEvent* aEvent) {
6245 if (aEvent && (aEvent->mMessage == eFocus || aEvent->mMessage == eBlur)) {
6246 nsCOMPtr<nsIContent> content = GetFocusedElement();
6247 return content.forget();
6248 }
6249
6250 if (mCurrentTargetContent) {
6251 nsCOMPtr<nsIContent> content = mCurrentTargetContent;
6252 return content.forget();
6253 }
6254
6255 nsCOMPtr<nsIContent> content;
6256 if (PresShell* presShell = mPresContext->GetPresShell()) {
6257 content = presShell->GetEventTargetContent(aEvent);
6258 }
6259
6260 // Some events here may set mCurrentTarget but not set the corresponding
6261 // event target in the PresShell.
6262 if (!content && mCurrentTarget) {
6263 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(content));
6264 }
6265
6266 return content.forget();
6267}
6268
6269static Element* GetLabelTarget(nsIContent* aPossibleLabel) {
6270 mozilla::dom::HTMLLabelElement* label =
6271 mozilla::dom::HTMLLabelElement::FromNode(aPossibleLabel);
6272 if (!label) return nullptr;
6273
6274 return label->GetLabeledElement();
6275}
6276
6277/* static */
6278inline void EventStateManager::DoStateChange(Element* aElement,
6279 ElementState aState,
6280 bool aAddState) {
6281 if (aAddState) {
6282 aElement->AddStates(aState);
6283 } else {
6284 aElement->RemoveStates(aState);
6285 }
6286}
6287
6288/* static */
6289inline void EventStateManager::DoStateChange(nsIContent* aContent,
6290 ElementState aState,
6291 bool aStateAdded) {
6292 if (aContent->IsElement()) {
6293 DoStateChange(aContent->AsElement(), aState, aStateAdded);
6294 }
6295}
6296
6297/* static */
6298void EventStateManager::UpdateAncestorState(nsIContent* aStartNode,
6299 nsIContent* aStopBefore,
6300 ElementState aState,
6301 bool aAddState) {
6302 for (; aStartNode && aStartNode != aStopBefore;
6303 aStartNode = aStartNode->GetFlattenedTreeParent()) {
6304 // We might be starting with a non-element (e.g. a text node) and
6305 // if someone is doing something weird might be ending with a
6306 // non-element too (e.g. a document fragment)
6307 if (!aStartNode->IsElement()) {
6308 continue;
6309 }
6310 Element* element = aStartNode->AsElement();
6311 DoStateChange(element, aState, aAddState);
6312 Element* labelTarget = GetLabelTarget(element);
6313 if (labelTarget) {
6314 DoStateChange(labelTarget, aState, aAddState);
6315 }
6316 }
6317
6318 if (aAddState) {
6319 // We might be in a situation where a node was in hover both
6320 // because it was hovered and because the label for it was
6321 // hovered, and while we stopped hovering the node the label is
6322 // still hovered. Or we might have had two nested labels for the
6323 // same node, and while one is no longer hovered the other still
6324 // is. In that situation, the label that's still hovered will be
6325 // aStopBefore or some ancestor of it, and the call we just made
6326 // to UpdateAncestorState with aAddState = false would have
6327 // removed the hover state from the node. But the node should
6328 // still be in hover state. To handle this situation we need to
6329 // keep walking up the tree and any time we find a label mark its
6330 // corresponding node as still in our state.
6331 for (; aStartNode; aStartNode = aStartNode->GetFlattenedTreeParent()) {
6332 if (!aStartNode->IsElement()) {
6333 continue;
6334 }
6335
6336 Element* labelTarget = GetLabelTarget(aStartNode->AsElement());
6337 if (labelTarget && !labelTarget->State().HasState(aState)) {
6338 DoStateChange(labelTarget, aState, true);
6339 }
6340 }
6341 }
6342}
6343
6344// static
6345bool CanContentHaveActiveState(nsIContent& aContent) {
6346 // Editable content can never become active since their default actions
6347 // are disabled. Watch out for editable content in native anonymous
6348 // subtrees though, as they belong to text controls.
6349 return !aContent.IsEditable() || aContent.IsInNativeAnonymousSubtree();
6350}
6351
6352bool EventStateManager::SetContentState(nsIContent* aContent,
6353 ElementState aState) {
6354 MOZ_ASSERT(ManagesState(aState), "Unexpected state")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ManagesState(aState))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ManagesState(aState)))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("ManagesState(aState)"
" (" "Unexpected state" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6354); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ManagesState(aState)"
") (" "Unexpected state" ")"); do { *((volatile int*)__null)
= 6354; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
6355
6356 nsCOMPtr<nsIContent> notifyContent1;
6357 nsCOMPtr<nsIContent> notifyContent2;
6358 bool updateAncestors;
6359
6360 if (aState == ElementState::HOVER || aState == ElementState::ACTIVE) {
6361 // Hover and active are hierarchical
6362 updateAncestors = true;
6363
6364 // check to see that this state is allowed by style. Check dragover too?
6365 // XXX Is this even what we want?
6366 if (mCurrentTarget &&
6367 mCurrentTarget->StyleUI()->UserInput() == StyleUserInput::None) {
6368 return false;
6369 }
6370
6371 if (aState == ElementState::ACTIVE) {
6372 if (aContent && !CanContentHaveActiveState(*aContent)) {
6373 aContent = nullptr;
6374 }
6375 if (aContent != mActiveContent) {
6376 notifyContent1 = aContent;
6377 notifyContent2 = mActiveContent;
6378 mActiveContent = aContent;
6379 }
6380 } else {
6381 NS_ASSERTION(aState == ElementState::HOVER, "How did that happen?")do { if (!(aState == ElementState::HOVER)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "How did that happen?", "aState == ElementState::HOVER", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6381); MOZ_PretendNoReturn(); } } while (0)
;
6382 nsIContent* newHover;
6383
6384 if (mPresContext->IsDynamic()) {
6385 newHover = aContent;
6386 } else {
6387 NS_ASSERTION(!aContent || aContent->GetComposedDoc() ==do { if (!(!aContent || aContent->GetComposedDoc() == mPresContext
->PresShell()->GetDocument())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected document", "!aContent || aContent->GetComposedDoc() == mPresContext->PresShell()->GetDocument()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6389); MOZ_PretendNoReturn(); } } while (0)
6388 mPresContext->PresShell()->GetDocument(),do { if (!(!aContent || aContent->GetComposedDoc() == mPresContext
->PresShell()->GetDocument())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected document", "!aContent || aContent->GetComposedDoc() == mPresContext->PresShell()->GetDocument()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6389); MOZ_PretendNoReturn(); } } while (0)
6389 "Unexpected document")do { if (!(!aContent || aContent->GetComposedDoc() == mPresContext
->PresShell()->GetDocument())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected document", "!aContent || aContent->GetComposedDoc() == mPresContext->PresShell()->GetDocument()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6389); MOZ_PretendNoReturn(); } } while (0)
;
6390 nsIFrame* frame = aContent ? aContent->GetPrimaryFrame() : nullptr;
6391 if (frame && nsLayoutUtils::IsViewportScrollbarFrame(frame)) {
6392 // The scrollbars of viewport should not ignore the hover state.
6393 // Because they are *not* the content of the web page.
6394 newHover = aContent;
6395 } else {
6396 // All contents of the web page should ignore the hover state.
6397 newHover = nullptr;
6398 }
6399 }
6400
6401 if (newHover != mHoverContent) {
6402 notifyContent1 = newHover;
6403 notifyContent2 = mHoverContent;
6404 mHoverContent = newHover;
6405 }
6406 }
6407 } else {
6408 updateAncestors = false;
6409 if (aState == ElementState::DRAGOVER) {
6410 if (aContent != sDragOverContent) {
6411 notifyContent1 = aContent;
6412 notifyContent2 = sDragOverContent;
6413 sDragOverContent = aContent;
6414 }
6415 } else if (aState == ElementState::URLTARGET) {
6416 if (aContent != mURLTargetContent) {
6417 notifyContent1 = aContent;
6418 notifyContent2 = mURLTargetContent;
6419 mURLTargetContent = aContent;
6420 }
6421 }
6422 }
6423
6424 // We need to keep track of which of notifyContent1 and notifyContent2 is
6425 // getting the state set and which is getting it unset. If both are
6426 // non-null, then notifyContent1 is having the state set and notifyContent2
6427 // is having it unset. But if one of them is null, we need to keep track of
6428 // the right thing for notifyContent1 explicitly.
6429 bool content1StateSet = true;
6430 if (!notifyContent1) {
6431 // This is ok because FindCommonAncestor wouldn't find anything
6432 // anyway if notifyContent1 is null.
6433 notifyContent1 = notifyContent2;
6434 notifyContent2 = nullptr;
6435 content1StateSet = false;
6436 }
6437
6438 if (notifyContent1 && mPresContext) {
6439 EnsureDocument(mPresContext);
6440 if (mDocument) {
6441 nsAutoScriptBlocker scriptBlocker;
6442
6443 if (updateAncestors) {
6444 nsCOMPtr<nsIContent> commonAncestor =
6445 FindCommonAncestor(notifyContent1, notifyContent2);
6446 if (notifyContent2) {
6447 // It's very important to first notify the state removal and
6448 // then the state addition, because due to labels it's
6449 // possible that we're removing state from some element but
6450 // then adding it again (say because mHoverContent changed
6451 // from a control to its label).
6452 UpdateAncestorState(notifyContent2, commonAncestor, aState, false);
6453 }
6454 UpdateAncestorState(notifyContent1, commonAncestor, aState,
6455 content1StateSet);
6456 } else {
6457 if (notifyContent2) {
6458 DoStateChange(notifyContent2, aState, false);
6459 }
6460 DoStateChange(notifyContent1, aState, content1StateSet);
6461 }
6462 }
6463 }
6464
6465 return true;
6466}
6467
6468void EventStateManager::RemoveNodeFromChainIfNeeded(ElementState aState,
6469 nsIContent* aContentRemoved,
6470 bool aNotify) {
6471 MOZ_ASSERT(aState == ElementState::HOVER || aState == ElementState::ACTIVE)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aState == ElementState::HOVER || aState == ElementState
::ACTIVE)>::isValid, "invalid assertion condition"); if ((
__builtin_expect(!!(!(!!(aState == ElementState::HOVER || aState
== ElementState::ACTIVE))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aState == ElementState::HOVER || aState == ElementState::ACTIVE"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6471); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aState == ElementState::HOVER || aState == ElementState::ACTIVE"
")"); do { *((volatile int*)__null) = 6471; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6472 if (!aContentRemoved->IsElement() ||
6473 !aContentRemoved->AsElement()->State().HasState(aState)) {
6474 return;
6475 }
6476
6477 nsCOMPtr<nsIContent>& leaf =
6478 aState == ElementState::HOVER ? mHoverContent : mActiveContent;
6479
6480 MOZ_ASSERT(leaf)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(leaf)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(leaf))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("leaf", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6480); AnnotateMozCrashReason("MOZ_ASSERT" "(" "leaf" ")");
do { *((volatile int*)__null) = 6480; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6481 // These two NS_ASSERTIONS below can fail for Shadow DOM sometimes, and it's
6482 // not clear how to best handle it, see
6483 // https://github.com/whatwg/html/issues/4795 and bug 1551621.
6484 NS_ASSERTION(do { if (!(nsContentUtils::ContentIsFlattenedTreeDescendantOf
(leaf, aContentRemoved))) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"Flat tree and active / hover chain got out of sync", "nsContentUtils::ContentIsFlattenedTreeDescendantOf(leaf, aContentRemoved)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6486); MOZ_PretendNoReturn(); } } while (0)
6485 nsContentUtils::ContentIsFlattenedTreeDescendantOf(leaf, aContentRemoved),do { if (!(nsContentUtils::ContentIsFlattenedTreeDescendantOf
(leaf, aContentRemoved))) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"Flat tree and active / hover chain got out of sync", "nsContentUtils::ContentIsFlattenedTreeDescendantOf(leaf, aContentRemoved)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6486); MOZ_PretendNoReturn(); } } while (0)
6486 "Flat tree and active / hover chain got out of sync")do { if (!(nsContentUtils::ContentIsFlattenedTreeDescendantOf
(leaf, aContentRemoved))) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"Flat tree and active / hover chain got out of sync", "nsContentUtils::ContentIsFlattenedTreeDescendantOf(leaf, aContentRemoved)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6486); MOZ_PretendNoReturn(); } } while (0)
;
6487
6488 nsIContent* newLeaf = aContentRemoved->GetFlattenedTreeParent();
6489 MOZ_ASSERT(!newLeaf || newLeaf->IsElement())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!newLeaf || newLeaf->IsElement())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!newLeaf || newLeaf->IsElement
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!newLeaf || newLeaf->IsElement()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6489); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!newLeaf || newLeaf->IsElement()"
")"); do { *((volatile int*)__null) = 6489; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6490 NS_ASSERTION(!newLeaf || newLeaf->AsElement()->State().HasState(aState),do { if (!(!newLeaf || newLeaf->AsElement()->State().HasState
(aState))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "State got out of sync because of shadow DOM"
, "!newLeaf || newLeaf->AsElement()->State().HasState(aState)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6491); MOZ_PretendNoReturn(); } } while (0)
6491 "State got out of sync because of shadow DOM")do { if (!(!newLeaf || newLeaf->AsElement()->State().HasState
(aState))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "State got out of sync because of shadow DOM"
, "!newLeaf || newLeaf->AsElement()->State().HasState(aState)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6491); MOZ_PretendNoReturn(); } } while (0)
;
6492 if (aNotify) {
6493 SetContentState(newLeaf, aState);
6494 } else {
6495 // We don't update the removed content's state here, since removing NAC
6496 // happens from layout and we don't really want to notify at that point or
6497 // what not.
6498 //
6499 // Also, NAC is not observable and NAC being removed will go away soon.
6500 leaf = newLeaf;
6501 }
6502 MOZ_ASSERT(leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(leaf == newLeaf || (aState == ElementState::ACTIVE &&
!leaf && !CanContentHaveActiveState(*newLeaf)))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(leaf == newLeaf || (aState == ElementState::ACTIVE &&
!leaf && !CanContentHaveActiveState(*newLeaf))))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf && !CanContentHaveActiveState(*newLeaf))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6503); AnnotateMozCrashReason("MOZ_ASSERT" "(" "leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf && !CanContentHaveActiveState(*newLeaf))"
")"); do { *((volatile int*)__null) = 6503; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6503 !CanContentHaveActiveState(*newLeaf)))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(leaf == newLeaf || (aState == ElementState::ACTIVE &&
!leaf && !CanContentHaveActiveState(*newLeaf)))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(leaf == newLeaf || (aState == ElementState::ACTIVE &&
!leaf && !CanContentHaveActiveState(*newLeaf))))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf && !CanContentHaveActiveState(*newLeaf))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6503); AnnotateMozCrashReason("MOZ_ASSERT" "(" "leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf && !CanContentHaveActiveState(*newLeaf))"
")"); do { *((volatile int*)__null) = 6503; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6504}
6505
6506void EventStateManager::NativeAnonymousContentRemoved(nsIContent* aContent) {
6507 MOZ_ASSERT(aContent->IsRootOfNativeAnonymousSubtree())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContent->IsRootOfNativeAnonymousSubtree())>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aContent->IsRootOfNativeAnonymousSubtree()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aContent->IsRootOfNativeAnonymousSubtree()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6507); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsRootOfNativeAnonymousSubtree()"
")"); do { *((volatile int*)__null) = 6507; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6508 RemoveNodeFromChainIfNeeded(ElementState::HOVER, aContent, false);
6509 RemoveNodeFromChainIfNeeded(ElementState::ACTIVE, aContent, false);
6510
6511 nsCOMPtr<nsIContent>& lastLeftMouseDownContent =
6512 mLastLeftMouseDownInfo.mLastMouseDownContent;
6513 if (lastLeftMouseDownContent &&
6514 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
6515 lastLeftMouseDownContent, aContent)) {
6516 lastLeftMouseDownContent = aContent->GetFlattenedTreeParent();
6517 }
6518
6519 nsCOMPtr<nsIContent>& lastMiddleMouseDownContent =
6520 mLastMiddleMouseDownInfo.mLastMouseDownContent;
6521 if (lastMiddleMouseDownContent &&
6522 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
6523 lastMiddleMouseDownContent, aContent)) {
6524 lastMiddleMouseDownContent = aContent->GetFlattenedTreeParent();
6525 }
6526
6527 nsCOMPtr<nsIContent>& lastRightMouseDownContent =
6528 mLastRightMouseDownInfo.mLastMouseDownContent;
6529 if (lastRightMouseDownContent &&
6530 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
6531 lastRightMouseDownContent, aContent)) {
6532 lastRightMouseDownContent = aContent->GetFlattenedTreeParent();
6533 }
6534}
6535
6536void EventStateManager::ContentRemoved(Document* aDocument,
6537 nsIContent* aContent) {
6538 /*
6539 * Anchor and area elements when focused or hovered might make the UI to show
6540 * the current link. We want to make sure that the UI gets informed when they
6541 * are actually removed from the DOM.
6542 */
6543 if (aContent->IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area) &&
6544 (aContent->AsElement()->State().HasAtLeastOneOfStates(
6545 ElementState::FOCUS | ElementState::HOVER))) {
6546 Element* element = aContent->AsElement();
6547 element->LeaveLink(element->GetPresContext(Element::eForComposedDoc));
6548 }
6549
6550 if (aContent->IsElement()) {
6551 if (RefPtr<nsPresContext> presContext = mPresContext) {
6552 IMEStateManager::OnRemoveContent(*presContext,
6553 MOZ_KnownLive(*aContent->AsElement())(*aContent->AsElement()));
6554 }
6555 WheelTransaction::OnRemoveElement(aContent);
6556 }
6557
6558 // inform the focus manager that the content is being removed. If this
6559 // content is focused, the focus will be removed without firing events.
6560 if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
6561 fm->ContentRemoved(aDocument, aContent);
6562 }
6563
6564 RemoveNodeFromChainIfNeeded(ElementState::HOVER, aContent, true);
6565 RemoveNodeFromChainIfNeeded(ElementState::ACTIVE, aContent, true);
6566
6567 if (sDragOverContent &&
6568 sDragOverContent->OwnerDoc() == aContent->OwnerDoc() &&
6569 nsContentUtils::ContentIsFlattenedTreeDescendantOf(sDragOverContent,
6570 aContent)) {
6571 sDragOverContent = nullptr;
6572 }
6573
6574 PointerEventHandler::ReleaseIfCaptureByDescendant(aContent);
6575
6576 if (mMouseEnterLeaveHelper) {
6577 const bool hadMouseOutTarget =
6578 mMouseEnterLeaveHelper->GetOutEventTarget() != nullptr;
6579 mMouseEnterLeaveHelper->ContentRemoved(*aContent);
6580 // If we lose the mouseout target, we need to dispatch mouseover on an
6581 // ancestor. For ensuring the chance to do it before next user input, we
6582 // need a synthetic mouse move.
6583 if (hadMouseOutTarget && !mMouseEnterLeaveHelper->GetOutEventTarget()) {
6584 if (PresShell* presShell =
6585 mPresContext ? mPresContext->GetPresShell() : nullptr) {
6586 presShell->SynthesizeMouseMove(false);
6587 }
6588 }
6589 }
6590 for (const auto& entry : mPointersEnterLeaveHelper) {
6591 if (entry.GetData()) {
6592 entry.GetData()->ContentRemoved(*aContent);
6593 }
6594 }
6595}
6596
6597void EventStateManager::TextControlRootWillBeRemoved(
6598 TextControlElement& aTextControlElement) {
6599 if (!mGestureDownInTextControl || !mGestureDownFrameOwner ||
6600 !mGestureDownFrameOwner->IsInNativeAnonymousSubtree()) {
6601 return;
6602 }
6603 // If we track gesture to start drag in aTextControlElement, we should keep
6604 // tracking it with aTextContrlElement itself for now because this may be
6605 // caused by reframing aTextControlElement which may not be intended by the
6606 // user.
6607 if (&aTextControlElement ==
6608 mGestureDownFrameOwner
6609 ->GetClosestNativeAnonymousSubtreeRootParentOrHost()) {
6610 mGestureDownFrameOwner = &aTextControlElement;
6611 }
6612}
6613
6614void EventStateManager::TextControlRootAdded(
6615 Element& aAnonymousDivElement, TextControlElement& aTextControlElement) {
6616 if (!mGestureDownInTextControl ||
6617 mGestureDownFrameOwner != &aTextControlElement) {
6618 return;
6619 }
6620 // If we track gesture to start drag in aTextControlElement, but the frame
6621 // owner is the text control element itself, the anonymous nodes in it are
6622 // recreated by a reframe. If so, we should keep tracking it with the
6623 // recreated native anonymous node.
6624 mGestureDownFrameOwner =
6625 aAnonymousDivElement.GetFirstChild()
6626 ? aAnonymousDivElement.GetFirstChild()
6627 : static_cast<nsIContent*>(&aAnonymousDivElement);
6628}
6629
6630bool EventStateManager::EventStatusOK(WidgetGUIEvent* aEvent) {
6631 return !(aEvent->mMessage == eMouseDown &&
6632 aEvent->AsMouseEvent()->mButton == MouseButton::ePrimary &&
6633 !sNormalLMouseEventInProcess);
6634}
6635
6636//-------------------------------------------
6637// Access Key Registration
6638//-------------------------------------------
6639void EventStateManager::RegisterAccessKey(Element* aElement, uint32_t aKey) {
6640 if (aElement && !mAccessKeys.Contains(aElement)) {
6641 mAccessKeys.AppendObject(aElement);
6642 }
6643}
6644
6645void EventStateManager::UnregisterAccessKey(Element* aElement, uint32_t aKey) {
6646 if (aElement) {
6647 mAccessKeys.RemoveObject(aElement);
6648 }
6649}
6650
6651uint32_t EventStateManager::GetRegisteredAccessKey(Element* aElement) {
6652 MOZ_ASSERT(aElement)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aElement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aElement))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aElement", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6652); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aElement" ")"
); do { *((volatile int*)__null) = 6652; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6653
6654 if (!mAccessKeys.Contains(aElement)) {
6655 return 0;
6656 }
6657
6658 nsAutoString accessKey;
6659 aElement->GetAttr(nsGkAtoms::accesskey, accessKey);
6660 return accessKey.First();
6661}
6662
6663void EventStateManager::EnsureDocument(nsPresContext* aPresContext) {
6664 if (!mDocument) mDocument = aPresContext->Document();
6665}
6666
6667void EventStateManager::FlushLayout(nsPresContext* aPresContext) {
6668 MOZ_ASSERT(aPresContext, "nullptr ptr")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresContext))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPresContext" " ("
"nullptr ptr" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6668); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresContext"
") (" "nullptr ptr" ")"); do { *((volatile int*)__null) = 6668
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
6669 if (RefPtr<PresShell> presShell = aPresContext->GetPresShell()) {
6670 presShell->FlushPendingNotifications(FlushType::InterruptibleLayout);
6671 }
6672}
6673
6674Element* EventStateManager::GetFocusedElement() {
6675 nsFocusManager* fm = nsFocusManager::GetFocusManager();
6676 EnsureDocument(mPresContext);
6677 if (!fm || !mDocument) {
6678 return nullptr;
6679 }
6680
6681 nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
6682 return nsFocusManager::GetFocusedDescendant(
6683 mDocument->GetWindow(), nsFocusManager::eOnlyCurrentWindow,
6684 getter_AddRefs(focusedWindow));
6685}
6686
6687//-------------------------------------------------------
6688// Return true if the docshell is visible
6689
6690bool EventStateManager::IsShellVisible(nsIDocShell* aShell) {
6691 NS_ASSERTION(aShell, "docshell is null")do { if (!(aShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "docshell is null"
, "aShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6691); MOZ_PretendNoReturn(); } } while (0)
;
6692
6693 nsCOMPtr<nsIBaseWindow> basewin = do_QueryInterface(aShell);
6694 if (!basewin) return true;
6695
6696 bool isVisible = true;
6697 basewin->GetVisibility(&isVisible);
6698
6699 // We should be doing some additional checks here so that
6700 // we don't tab into hidden tabs of tabbrowser. -bryner
6701
6702 return isVisible;
6703}
6704
6705nsresult EventStateManager::DoContentCommandEvent(
6706 WidgetContentCommandEvent* aEvent) {
6707 EnsureDocument(mPresContext);
6708 NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(mDocument)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mDocument" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6708); return NS_ERROR_FAILURE; } } while (false)
;
6709 nsCOMPtr<nsPIDOMWindowOuter> window(mDocument->GetWindow());
6710 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(window)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "window" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6710); return NS_ERROR_FAILURE; } } while (false)
;
6711
6712 nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
6713 NS_ENSURE_TRUE(root, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(root)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "root" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6713); return NS_ERROR_FAILURE; } } while (false)
;
6714 const char* cmd;
6715 switch (aEvent->mMessage) {
6716 case eContentCommandCut:
6717 cmd = "cmd_cut";
6718 break;
6719 case eContentCommandCopy:
6720 cmd = "cmd_copy";
6721 break;
6722 case eContentCommandPaste:
6723 cmd = "cmd_paste";
6724 break;
6725 case eContentCommandDelete:
6726 cmd = "cmd_delete";
6727 break;
6728 case eContentCommandUndo:
6729 cmd = "cmd_undo";
6730 break;
6731 case eContentCommandRedo:
6732 cmd = "cmd_redo";
6733 break;
6734 case eContentCommandPasteTransferable:
6735 cmd = "cmd_pasteTransferable";
6736 break;
6737 case eContentCommandLookUpDictionary:
6738 cmd = "cmd_lookUpDictionary";
6739 break;
6740 default:
6741 return NS_ERROR_NOT_IMPLEMENTED;
6742 }
6743 // If user tries to do something, user must try to do it in visible window.
6744 // So, let's retrieve controller of visible window.
6745 nsCOMPtr<nsIController> controller;
6746 nsresult rv =
6747 root->GetControllerForCommand(cmd, true, getter_AddRefs(controller));
6748 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6748); return rv; } } while (false)
;
6749 if (!controller) {
6750 // When GetControllerForCommand succeeded but there is no controller, the
6751 // command isn't supported.
6752 aEvent->mIsEnabled = false;
6753 } else {
6754 bool canDoIt;
6755 rv = controller->IsCommandEnabled(cmd, &canDoIt);
6756 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6756); return rv; } } while (false)
;
6757 aEvent->mIsEnabled = canDoIt;
6758 if (canDoIt && !aEvent->mOnlyEnabledCheck) {
6759 switch (aEvent->mMessage) {
6760 case eContentCommandPasteTransferable: {
6761 BrowserParent* remote = BrowserParent::GetFocused();
6762 if (remote) {
6763 IPCTransferable ipcTransferable;
6764 nsContentUtils::TransferableToIPCTransferable(
6765 aEvent->mTransferable, &ipcTransferable, false,
6766 remote->Manager());
6767 remote->SendPasteTransferable(std::move(ipcTransferable));
6768 rv = NS_OK;
6769 } else {
6770 nsCOMPtr<nsICommandController> commandController =
6771 do_QueryInterface(controller);
6772 NS_ENSURE_STATE(commandController)do { if ((__builtin_expect(!!(!(commandController)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "commandController" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6772); return NS_ERROR_UNEXPECTED; } } while (false)
;
6773
6774 RefPtr<nsCommandParams> params = new nsCommandParams();
6775 rv = params->SetISupports("transferable", aEvent->mTransferable);
6776 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6776)
) {
6777 return rv;
6778 }
6779 rv = commandController->DoCommandWithParams(cmd, params);
6780 }
6781 break;
6782 }
6783
6784 case eContentCommandLookUpDictionary: {
6785 nsCOMPtr<nsICommandController> commandController =
6786 do_QueryInterface(controller);
6787 if (NS_WARN_IF(!commandController)NS_warn_if_impl(!commandController, "!commandController", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6787)
) {
6788 return NS_ERROR_FAILURE;
6789 }
6790
6791 RefPtr<nsCommandParams> params = new nsCommandParams();
6792 rv = params->SetInt("x", aEvent->mRefPoint.x);
6793 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6793)
) {
6794 return rv;
6795 }
6796
6797 rv = params->SetInt("y", aEvent->mRefPoint.y);
6798 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6798)
) {
6799 return rv;
6800 }
6801
6802 rv = commandController->DoCommandWithParams(cmd, params);
6803 break;
6804 }
6805
6806 default:
6807 rv = controller->DoCommand(cmd);
6808 break;
6809 }
6810 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6810); return rv; } } while (false)
;
6811 }
6812 }
6813 aEvent->mSucceeded = true;
6814 return NS_OK;
6815}
6816
6817nsresult EventStateManager::DoContentCommandInsertTextEvent(
6818 WidgetContentCommandEvent* aEvent) {
6819 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6819); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 6819; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6820 MOZ_ASSERT(aEvent->mMessage == eContentCommandInsertText)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eContentCommandInsertText)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aEvent->mMessage == eContentCommandInsertText))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eContentCommandInsertText"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6820); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eContentCommandInsertText"
")"); do { *((volatile int*)__null) = 6820; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6821 MOZ_DIAGNOSTIC_ASSERT(aEvent->mString.isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mString.isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mString.isSome())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->mString.isSome()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6821); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aEvent->mString.isSome()"
")"); do { *((volatile int*)__null) = 6821; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6822 MOZ_DIAGNOSTIC_ASSERT(!aEvent->mString.ref().IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEvent->mString.ref().IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aEvent->mString.ref().IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aEvent->mString.ref().IsEmpty()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6822); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!aEvent->mString.ref().IsEmpty()"
")"); do { *((volatile int*)__null) = 6822; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6823
6824 aEvent->mIsEnabled = false;
6825 aEvent->mSucceeded = false;
6826
6827 NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(mPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6827); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
6828
6829 if (XRE_IsParentProcess()) {
6830 // Handle it in focused content process if there is.
6831 if (BrowserParent* remote = BrowserParent::GetFocused()) {
6832 remote->SendInsertText(aEvent->mString.ref());
6833 aEvent->mIsEnabled = true; // XXX it can be a lie...
6834 aEvent->mSucceeded = true;
6835 return NS_OK;
6836 }
6837 }
6838
6839 // If there is no active editor in this process, we should treat the command
6840 // is disabled.
6841 RefPtr<EditorBase> activeEditor =
6842 nsContentUtils::GetActiveEditor(mPresContext);
6843 if (!activeEditor) {
6844 aEvent->mSucceeded = true;
6845 return NS_OK;
6846 }
6847
6848 nsresult rv = activeEditor->InsertTextAsAction(aEvent->mString.ref());
6849 aEvent->mIsEnabled = rv != NS_SUCCESS_DOM_NO_OPERATION;
6850 aEvent->mSucceeded = NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)));
6851 return NS_OK;
6852}
6853
6854nsresult EventStateManager::DoContentCommandReplaceTextEvent(
6855 WidgetContentCommandEvent* aEvent) {
6856 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6856); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 6856; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6857 MOZ_ASSERT(aEvent->mMessage == eContentCommandReplaceText)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eContentCommandReplaceText)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aEvent->mMessage == eContentCommandReplaceText)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eContentCommandReplaceText"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6857); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eContentCommandReplaceText"
")"); do { *((volatile int*)__null) = 6857; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6858 MOZ_DIAGNOSTIC_ASSERT(aEvent->mString.isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mString.isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mString.isSome())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->mString.isSome()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6858); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aEvent->mString.isSome()"
")"); do { *((volatile int*)__null) = 6858; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6859 MOZ_DIAGNOSTIC_ASSERT(!aEvent->mString.ref().IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEvent->mString.ref().IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aEvent->mString.ref().IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aEvent->mString.ref().IsEmpty()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6859); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!aEvent->mString.ref().IsEmpty()"
")"); do { *((volatile int*)__null) = 6859; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6860
6861 aEvent->mIsEnabled = false;
6862 aEvent->mSucceeded = false;
6863
6864 NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(mPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6864); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
6865
6866 if (XRE_IsParentProcess()) {
6867 // Handle it in focused content process if there is.
6868 if (BrowserParent* remote = BrowserParent::GetFocused()) {
6869 Unused << remote->SendReplaceText(
6870 aEvent->mSelection.mReplaceSrcString, aEvent->mString.ref(),
6871 aEvent->mSelection.mOffset, aEvent->mSelection.mPreventSetSelection);
6872 aEvent->mIsEnabled = true; // XXX it can be a lie...
6873 aEvent->mSucceeded = true;
6874 return NS_OK;
6875 }
6876 }
6877
6878 // If there is no active editor in this process, we should treat the command
6879 // is disabled.
6880 RefPtr<EditorBase> activeEditor =
6881 nsContentUtils::GetActiveEditor(mPresContext);
6882 if (NS_WARN_IF(!activeEditor)NS_warn_if_impl(!activeEditor, "!activeEditor", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6882)
) {
6883 aEvent->mSucceeded = true;
6884 return NS_OK;
6885 }
6886
6887 RefPtr<TextComposition> composition =
6888 IMEStateManager::GetTextCompositionFor(mPresContext);
6889 if (NS_WARN_IF(composition)NS_warn_if_impl(composition, "composition", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6889)
) {
6890 // We don't support replace text action during composition.
6891 aEvent->mSucceeded = true;
6892 return NS_OK;
6893 }
6894
6895 ContentEventHandler handler(mPresContext);
6896 RefPtr<nsRange> range = handler.GetRangeFromFlatTextOffset(
6897 aEvent, aEvent->mSelection.mOffset,
6898 aEvent->mSelection.mReplaceSrcString.Length());
6899 if (NS_WARN_IF(!range)NS_warn_if_impl(!range, "!range", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6899)
) {
6900 aEvent->mSucceeded = false;
6901 return NS_OK;
6902 }
6903
6904 // If original replacement text isn't matched with selection text, throws
6905 // error.
6906 nsAutoString targetStr;
6907 nsresult rv = handler.GenerateFlatTextContent(range, targetStr);
6908 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6908)
) {
6909 aEvent->mSucceeded = false;
6910 return NS_OK;
6911 }
6912 if (!aEvent->mSelection.mReplaceSrcString.Equals(targetStr)) {
6913 aEvent->mSucceeded = false;
6914 return NS_OK;
6915 }
6916
6917 rv = activeEditor->ReplaceTextAsAction(
6918 aEvent->mString.ref(), range,
6919 TextEditor::AllowBeforeInputEventCancelable::Yes,
6920 aEvent->mSelection.mPreventSetSelection
6921 ? EditorBase::PreventSetSelection::Yes
6922 : EditorBase::PreventSetSelection::No);
6923 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6923)
) {
6924 aEvent->mSucceeded = false;
6925 return NS_OK;
6926 }
6927
6928 aEvent->mIsEnabled = rv != NS_SUCCESS_DOM_NO_OPERATION;
6929 aEvent->mSucceeded = true;
6930 return NS_OK;
6931}
6932
6933nsresult EventStateManager::DoContentCommandScrollEvent(
6934 WidgetContentCommandEvent* aEvent) {
6935 NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(mPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6935); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
6936 PresShell* presShell = mPresContext->GetPresShell();
6937 NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(presShell)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "presShell" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6937); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
6938 NS_ENSURE_TRUE(aEvent->mScroll.mAmount != 0, NS_ERROR_INVALID_ARG)do { if ((__builtin_expect(!!(!(aEvent->mScroll.mAmount !=
0)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE("
"aEvent->mScroll.mAmount != 0" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6938); return NS_ERROR_INVALID_ARG; } } while (false)
;
6939
6940 ScrollUnit scrollUnit;
6941 switch (aEvent->mScroll.mUnit) {
6942 case WidgetContentCommandEvent::eCmdScrollUnit_Line:
6943 scrollUnit = ScrollUnit::LINES;
6944 break;
6945 case WidgetContentCommandEvent::eCmdScrollUnit_Page:
6946 scrollUnit = ScrollUnit::PAGES;
6947 break;
6948 case WidgetContentCommandEvent::eCmdScrollUnit_Whole:
6949 scrollUnit = ScrollUnit::WHOLE;
6950 break;
6951 default:
6952 return NS_ERROR_INVALID_ARG;
6953 }
6954
6955 aEvent->mSucceeded = true;
6956
6957 ScrollContainerFrame* sf =
6958 presShell->GetScrollContainerFrameToScroll(layers::EitherScrollDirection);
6959 aEvent->mIsEnabled =
6960 sf ? (aEvent->mScroll.mIsHorizontal ? WheelHandlingUtils::CanScrollOn(
6961 sf, aEvent->mScroll.mAmount, 0)
6962 : WheelHandlingUtils::CanScrollOn(
6963 sf, 0, aEvent->mScroll.mAmount))
6964 : false;
6965
6966 if (!aEvent->mIsEnabled || aEvent->mOnlyEnabledCheck) {
6967 return NS_OK;
6968 }
6969
6970 nsIntPoint pt(0, 0);
6971 if (aEvent->mScroll.mIsHorizontal) {
6972 pt.x = aEvent->mScroll.mAmount;
6973 } else {
6974 pt.y = aEvent->mScroll.mAmount;
6975 }
6976
6977 // The caller may want synchronous scrolling.
6978 sf->ScrollBy(pt, scrollUnit, ScrollMode::Instant);
6979 return NS_OK;
6980}
6981
6982void EventStateManager::SetActiveManager(EventStateManager* aNewESM,
6983 nsIContent* aContent) {
6984 if (sActiveESM && aNewESM != sActiveESM) {
6985 sActiveESM->SetContentState(nullptr, ElementState::ACTIVE);
6986 }
6987 sActiveESM = aNewESM;
6988 if (sActiveESM && aContent) {
6989 sActiveESM->SetContentState(aContent, ElementState::ACTIVE);
6990 }
6991}
6992
6993void EventStateManager::ClearGlobalActiveContent(EventStateManager* aClearer) {
6994 if (aClearer) {
6995 aClearer->SetContentState(nullptr, ElementState::ACTIVE);
6996 if (sDragOverContent) {
6997 aClearer->SetContentState(nullptr, ElementState::DRAGOVER);
6998 }
6999 }
7000 if (sActiveESM && aClearer != sActiveESM) {
7001 sActiveESM->SetContentState(nullptr, ElementState::ACTIVE);
7002 }
7003 sActiveESM = nullptr;
7004}
7005
7006/******************************************************************/
7007/* mozilla::EventStateManager::DeltaAccumulator */
7008/******************************************************************/
7009
7010void EventStateManager::DeltaAccumulator::InitLineOrPageDelta(
7011 nsIFrame* aTargetFrame, EventStateManager* aESM, WidgetWheelEvent* aEvent) {
7012 MOZ_ASSERT(aESM)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aESM)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aESM))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aESM", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7012); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aESM" ")");
do { *((volatile int*)__null) = 7012; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7013 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7013); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 7013; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7014
7015 // Reset if the previous wheel event is too old.
7016 if (!mLastTime.IsNull()) {
7017 TimeDuration duration = TimeStamp::Now() - mLastTime;
7018 if (duration.ToMilliseconds() >
7019 StaticPrefs::mousewheel_transaction_timeout()) {
7020 Reset();
7021 }
7022 }
7023 // If we have accumulated delta, we may need to reset it.
7024 if (IsInTransaction()) {
7025 // If wheel event type is changed, reset the values.
7026 if (mHandlingDeltaMode != aEvent->mDeltaMode ||
7027 mIsNoLineOrPageDeltaDevice != aEvent->mIsNoLineOrPageDelta) {
7028 Reset();
7029 } else {
7030 // If the delta direction is changed, we should reset only the
7031 // accumulated values.
7032 if (mX && aEvent->mDeltaX && ((aEvent->mDeltaX > 0.0) != (mX > 0.0))) {
7033 mX = mPendingScrollAmountX = 0.0;
7034 }
7035 if (mY && aEvent->mDeltaY && ((aEvent->mDeltaY > 0.0) != (mY > 0.0))) {
7036 mY = mPendingScrollAmountY = 0.0;
7037 }
7038 }
7039 }
7040
7041 mHandlingDeltaMode = aEvent->mDeltaMode;
7042 mIsNoLineOrPageDeltaDevice = aEvent->mIsNoLineOrPageDelta;
7043
7044 {
7045 ScrollContainerFrame* scrollTarget = aESM->ComputeScrollTarget(
7046 aTargetFrame, aEvent, COMPUTE_DEFAULT_ACTION_TARGET);
7047 nsPresContext* pc = scrollTarget ? scrollTarget->PresContext()
7048 : aTargetFrame->PresContext();
7049 aEvent->mScrollAmount = aESM->GetScrollAmount(pc, aEvent, scrollTarget);
7050 }
7051
7052 // If it's handling neither a device that does not provide line or page deltas
7053 // nor delta values multiplied by prefs, we must not modify lineOrPageDelta
7054 // values.
7055 // TODO(emilio): Does this care about overridden scroll speed?
7056 if (!mIsNoLineOrPageDeltaDevice &&
7057 !EventStateManager::WheelPrefs::GetInstance()
7058 ->NeedToComputeLineOrPageDelta(aEvent)) {
7059 // Set the delta values to mX and mY. They would be used when above block
7060 // resets mX/mY/mPendingScrollAmountX/mPendingScrollAmountY if the direction
7061 // is changed.
7062 // NOTE: We shouldn't accumulate the delta values, it might could cause
7063 // overflow even though it's not a realistic situation.
7064 if (aEvent->mDeltaX) {
7065 mX = aEvent->mDeltaX;
7066 }
7067 if (aEvent->mDeltaY) {
7068 mY = aEvent->mDeltaY;
7069 }
7070 mLastTime = TimeStamp::Now();
7071 return;
7072 }
7073
7074 mX += aEvent->mDeltaX;
7075 mY += aEvent->mDeltaY;
7076
7077 if (mHandlingDeltaMode == WheelEvent_Binding::DOM_DELTA_PIXEL) {
7078 // Records pixel delta values and init mLineOrPageDeltaX and
7079 // mLineOrPageDeltaY for wheel events which are caused by pixel only
7080 // devices. Ignore mouse wheel transaction for computing this. The
7081 // lineOrPageDelta values will be used by dispatching legacy
7082 // eMouseScrollEventClass (DOMMouseScroll) but not be used for scrolling
7083 // of default action. The transaction should be used only for the default
7084 // action.
7085 auto scrollAmountInCSSPixels =
7086 CSSIntSize::FromAppUnitsRounded(aEvent->mScrollAmount);
7087
7088 aEvent->mLineOrPageDeltaX = RoundDown(mX) / scrollAmountInCSSPixels.width;
7089 aEvent->mLineOrPageDeltaY = RoundDown(mY) / scrollAmountInCSSPixels.height;
7090
7091 mX -= aEvent->mLineOrPageDeltaX * scrollAmountInCSSPixels.width;
7092 mY -= aEvent->mLineOrPageDeltaY * scrollAmountInCSSPixels.height;
7093 } else {
7094 aEvent->mLineOrPageDeltaX = RoundDown(mX);
7095 aEvent->mLineOrPageDeltaY = RoundDown(mY);
7096 mX -= aEvent->mLineOrPageDeltaX;
7097 mY -= aEvent->mLineOrPageDeltaY;
7098 }
7099
7100 mLastTime = TimeStamp::Now();
7101}
7102
7103void EventStateManager::DeltaAccumulator::Reset() {
7104 mX = mY = 0.0;
7105 mPendingScrollAmountX = mPendingScrollAmountY = 0.0;
7106 mHandlingDeltaMode = UINT32_MAX(4294967295U);
7107 mIsNoLineOrPageDeltaDevice = false;
7108}
7109
7110nsIntPoint
7111EventStateManager::DeltaAccumulator::ComputeScrollAmountForDefaultAction(
7112 WidgetWheelEvent* aEvent, const nsIntSize& aScrollAmountInDevPixels) {
7113 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7113); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 7113; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7114
7115 DeltaValues acceleratedDelta = WheelTransaction::AccelerateWheelDelta(aEvent);
7116
7117 nsIntPoint result(0, 0);
7118 if (aEvent->mDeltaMode == WheelEvent_Binding::DOM_DELTA_PIXEL) {
7119 mPendingScrollAmountX += acceleratedDelta.deltaX;
7120 mPendingScrollAmountY += acceleratedDelta.deltaY;
7121 } else {
7122 mPendingScrollAmountX +=
7123 aScrollAmountInDevPixels.width * acceleratedDelta.deltaX;
7124 mPendingScrollAmountY +=
7125 aScrollAmountInDevPixels.height * acceleratedDelta.deltaY;
7126 }
7127 result.x = RoundDown(mPendingScrollAmountX);
7128 result.y = RoundDown(mPendingScrollAmountY);
7129 mPendingScrollAmountX -= result.x;
7130 mPendingScrollAmountY -= result.y;
7131
7132 return result;
7133}
7134
7135/******************************************************************/
7136/* mozilla::EventStateManager::WheelPrefs */
7137/******************************************************************/
7138
7139// static
7140EventStateManager::WheelPrefs* EventStateManager::WheelPrefs::GetInstance() {
7141 if (!sInstance) {
7142 sInstance = new WheelPrefs();
7143 }
7144 return sInstance;
7145}
7146
7147// static
7148void EventStateManager::WheelPrefs::Shutdown() {
7149 delete sInstance;
7150 sInstance = nullptr;
7151}
7152
7153// static
7154void EventStateManager::WheelPrefs::OnPrefChanged(const char* aPrefName,
7155 void* aClosure) {
7156 // forget all prefs, it's not problem for performance.
7157 sInstance->Reset();
7158 DeltaAccumulator::GetInstance()->Reset();
7159}
7160
7161EventStateManager::WheelPrefs::WheelPrefs() {
7162 Reset();
7163 Preferences::RegisterPrefixCallback(OnPrefChanged, "mousewheel.");
7164}
7165
7166EventStateManager::WheelPrefs::~WheelPrefs() {
7167 Preferences::UnregisterPrefixCallback(OnPrefChanged, "mousewheel.");
7168}
7169
7170void EventStateManager::WheelPrefs::Reset() { memset(mInit, 0, sizeof(mInit)); }
7171
7172EventStateManager::WheelPrefs::Index EventStateManager::WheelPrefs::GetIndexFor(
7173 const WidgetWheelEvent* aEvent) {
7174 if (!aEvent) {
7175 return INDEX_DEFAULT;
7176 }
7177
7178 Modifiers modifiers = (aEvent->mModifiers & (MODIFIER_ALT | MODIFIER_CONTROL |
7179 MODIFIER_META | MODIFIER_SHIFT));
7180
7181 switch (modifiers) {
7182 case MODIFIER_ALT:
7183 return INDEX_ALT;
7184 case MODIFIER_CONTROL:
7185 return INDEX_CONTROL;
7186 case MODIFIER_META:
7187 return INDEX_META;
7188 case MODIFIER_SHIFT:
7189 return INDEX_SHIFT;
7190 default:
7191 // If two or more modifier keys are pressed, we should use default
7192 // settings.
7193 return INDEX_DEFAULT;
7194 }
7195}
7196
7197void EventStateManager::WheelPrefs::GetBasePrefName(
7198 EventStateManager::WheelPrefs::Index aIndex, nsACString& aBasePrefName) {
7199 aBasePrefName.AssignLiteral("mousewheel.");
7200 switch (aIndex) {
7201 case INDEX_ALT:
7202 aBasePrefName.AppendLiteral("with_alt.");
7203 break;
7204 case INDEX_CONTROL:
7205 aBasePrefName.AppendLiteral("with_control.");
7206 break;
7207 case INDEX_META:
7208 aBasePrefName.AppendLiteral("with_meta.");
7209 break;
7210 case INDEX_SHIFT:
7211 aBasePrefName.AppendLiteral("with_shift.");
7212 break;
7213 case INDEX_DEFAULT:
7214 default:
7215 aBasePrefName.AppendLiteral("default.");
7216 break;
7217 }
7218}
7219
7220void EventStateManager::WheelPrefs::Init(
7221 EventStateManager::WheelPrefs::Index aIndex) {
7222 if (mInit[aIndex]) {
7223 return;
7224 }
7225 mInit[aIndex] = true;
7226
7227 nsAutoCString basePrefName;
7228 GetBasePrefName(aIndex, basePrefName);
7229
7230 nsAutoCString prefNameX(basePrefName);
7231 prefNameX.AppendLiteral("delta_multiplier_x");
7232 mMultiplierX[aIndex] =
7233 static_cast<double>(Preferences::GetInt(prefNameX.get(), 100)) / 100;
7234
7235 nsAutoCString prefNameY(basePrefName);
7236 prefNameY.AppendLiteral("delta_multiplier_y");
7237 mMultiplierY[aIndex] =
7238 static_cast<double>(Preferences::GetInt(prefNameY.get(), 100)) / 100;
7239
7240 nsAutoCString prefNameZ(basePrefName);
7241 prefNameZ.AppendLiteral("delta_multiplier_z");
7242 mMultiplierZ[aIndex] =
7243 static_cast<double>(Preferences::GetInt(prefNameZ.get(), 100)) / 100;
7244
7245 nsAutoCString prefNameAction(basePrefName);
7246 prefNameAction.AppendLiteral("action");
7247 int32_t action = Preferences::GetInt(prefNameAction.get(), ACTION_SCROLL);
7248 if (action < int32_t(ACTION_NONE) || action > int32_t(ACTION_LAST)) {
7249 NS_WARNING("Unsupported action pref value, replaced with 'Scroll'.")NS_DebugBreak(NS_DEBUG_WARNING, "Unsupported action pref value, replaced with 'Scroll'."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7249)
;
7250 action = ACTION_SCROLL;
7251 }
7252 mActions[aIndex] = static_cast<Action>(action);
7253
7254 // Compute action values overridden by .override_x pref.
7255 // At present, override is possible only for the x-direction
7256 // because this pref is introduced mainly for tilt wheels.
7257 // Note that ACTION_HORIZONTALIZED_SCROLL isn't a valid value for this pref
7258 // because it affects only to deltaY.
7259 prefNameAction.AppendLiteral(".override_x");
7260 int32_t actionOverrideX = Preferences::GetInt(prefNameAction.get(), -1);
7261 if (actionOverrideX < -1 || actionOverrideX > int32_t(ACTION_LAST) ||
7262 actionOverrideX == ACTION_HORIZONTALIZED_SCROLL) {
7263 NS_WARNING("Unsupported action override pref value, didn't override.")NS_DebugBreak(NS_DEBUG_WARNING, "Unsupported action override pref value, didn't override."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7263)
;
7264 actionOverrideX = -1;
7265 }
7266 mOverriddenActionsX[aIndex] = (actionOverrideX == -1)
7267 ? static_cast<Action>(action)
7268 : static_cast<Action>(actionOverrideX);
7269}
7270
7271void EventStateManager::WheelPrefs::GetMultiplierForDeltaXAndY(
7272 const WidgetWheelEvent* aEvent, Index aIndex, double* aMultiplierForDeltaX,
7273 double* aMultiplierForDeltaY) {
7274 *aMultiplierForDeltaX = mMultiplierX[aIndex];
7275 *aMultiplierForDeltaY = mMultiplierY[aIndex];
7276 // If the event has been horizontalized(I.e. treated as a horizontal wheel
7277 // scroll for a vertical wheel scroll), then we should swap mMultiplierX and
7278 // mMultiplierY. By doing this, multipliers will still apply to the delta
7279 // values they origianlly corresponded to.
7280 if (aEvent->mDeltaValuesHorizontalizedForDefaultHandler &&
7281 ComputeActionFor(aEvent) == ACTION_HORIZONTALIZED_SCROLL) {
7282 std::swap(*aMultiplierForDeltaX, *aMultiplierForDeltaY);
7283 }
7284}
7285
7286void EventStateManager::WheelPrefs::ApplyUserPrefsToDelta(
7287 WidgetWheelEvent* aEvent) {
7288 if (aEvent->mCustomizedByUserPrefs) {
7289 return;
7290 }
7291
7292 Index index = GetIndexFor(aEvent);
7293 Init(index);
7294
7295 double multiplierForDeltaX = 1.0, multiplierForDeltaY = 1.0;
7296 GetMultiplierForDeltaXAndY(aEvent, index, &multiplierForDeltaX,
7297 &multiplierForDeltaY);
7298 aEvent->mDeltaX *= multiplierForDeltaX;
7299 aEvent->mDeltaY *= multiplierForDeltaY;
7300 aEvent->mDeltaZ *= mMultiplierZ[index];
7301
7302 // If the multiplier is 1.0 or -1.0, i.e., it doesn't change the absolute
7303 // value, we should use lineOrPageDelta values which were set by widget.
7304 // Otherwise, we need to compute them from accumulated delta values.
7305 if (!NeedToComputeLineOrPageDelta(aEvent)) {
7306 aEvent->mLineOrPageDeltaX *= static_cast<int32_t>(multiplierForDeltaX);
7307 aEvent->mLineOrPageDeltaY *= static_cast<int32_t>(multiplierForDeltaY);
7308 } else {
7309 aEvent->mLineOrPageDeltaX = 0;
7310 aEvent->mLineOrPageDeltaY = 0;
7311 }
7312
7313 aEvent->mCustomizedByUserPrefs =
7314 ((mMultiplierX[index] != 1.0) || (mMultiplierY[index] != 1.0) ||
7315 (mMultiplierZ[index] != 1.0));
7316}
7317
7318void EventStateManager::WheelPrefs::CancelApplyingUserPrefsFromOverflowDelta(
7319 WidgetWheelEvent* aEvent) {
7320 Index index = GetIndexFor(aEvent);
7321 Init(index);
7322
7323 // XXX If the multiplier pref value is negative, the scroll direction was
7324 // changed and caused to scroll different direction. In such case,
7325 // this method reverts the sign of overflowDelta. Does it make widget
7326 // happy? Although, widget can know the pref applied delta values by
7327 // referrencing the deltaX and deltaY of the event.
7328
7329 double multiplierForDeltaX = 1.0, multiplierForDeltaY = 1.0;
7330 GetMultiplierForDeltaXAndY(aEvent, index, &multiplierForDeltaX,
7331 &multiplierForDeltaY);
7332 if (multiplierForDeltaX) {
7333 aEvent->mOverflowDeltaX /= multiplierForDeltaX;
7334 }
7335 if (multiplierForDeltaY) {
7336 aEvent->mOverflowDeltaY /= multiplierForDeltaY;
7337 }
7338}
7339
7340EventStateManager::WheelPrefs::Action
7341EventStateManager::WheelPrefs::ComputeActionFor(
7342 const WidgetWheelEvent* aEvent) {
7343 Index index = GetIndexFor(aEvent);
7344 Init(index);
7345
7346 bool deltaXPreferred = (Abs(aEvent->mDeltaX) > Abs(aEvent->mDeltaY) &&
7347 Abs(aEvent->mDeltaX) > Abs(aEvent->mDeltaZ));
7348 Action* actions = deltaXPreferred ? mOverriddenActionsX : mActions;
7349 if (actions[index] == ACTION_NONE || actions[index] == ACTION_SCROLL ||
7350 actions[index] == ACTION_HORIZONTALIZED_SCROLL) {
7351 return actions[index];
7352 }
7353
7354 // Momentum events shouldn't run special actions.
7355 if (aEvent->mIsMomentum) {
7356 // Use the default action. Note that user might kill the wheel scrolling.
7357 Init(INDEX_DEFAULT);
7358 if (actions[INDEX_DEFAULT] == ACTION_SCROLL ||
7359 actions[INDEX_DEFAULT] == ACTION_HORIZONTALIZED_SCROLL) {
7360 return actions[INDEX_DEFAULT];
7361 }
7362 return ACTION_NONE;
7363 }
7364
7365 return actions[index];
7366}
7367
7368bool EventStateManager::WheelPrefs::NeedToComputeLineOrPageDelta(
7369 const WidgetWheelEvent* aEvent) {
7370 Index index = GetIndexFor(aEvent);
7371 Init(index);
7372
7373 return (mMultiplierX[index] != 1.0 && mMultiplierX[index] != -1.0) ||
7374 (mMultiplierY[index] != 1.0 && mMultiplierY[index] != -1.0);
7375}
7376
7377void EventStateManager::WheelPrefs::GetUserPrefsForEvent(
7378 const WidgetWheelEvent* aEvent, double* aOutMultiplierX,
7379 double* aOutMultiplierY) {
7380 Index index = GetIndexFor(aEvent);
7381 Init(index);
7382
7383 double multiplierForDeltaX = 1.0, multiplierForDeltaY = 1.0;
7384 GetMultiplierForDeltaXAndY(aEvent, index, &multiplierForDeltaX,
7385 &multiplierForDeltaY);
7386 *aOutMultiplierX = multiplierForDeltaX;
7387 *aOutMultiplierY = multiplierForDeltaY;
7388}
7389
7390// static
7391Maybe<layers::APZWheelAction> EventStateManager::APZWheelActionFor(
7392 const WidgetWheelEvent* aEvent) {
7393 if (aEvent->mMessage != eWheel) {
7394 return Nothing();
7395 }
7396 WheelPrefs::Action action =
7397 WheelPrefs::GetInstance()->ComputeActionFor(aEvent);
7398 switch (action) {
7399 case WheelPrefs::ACTION_SCROLL:
7400 case WheelPrefs::ACTION_HORIZONTALIZED_SCROLL:
7401 return Some(layers::APZWheelAction::Scroll);
7402 case WheelPrefs::ACTION_PINCH_ZOOM:
7403 return Some(layers::APZWheelAction::PinchZoom);
7404 default:
7405 return Nothing();
7406 }
7407}
7408
7409// static
7410WheelDeltaAdjustmentStrategy EventStateManager::GetWheelDeltaAdjustmentStrategy(
7411 const WidgetWheelEvent& aEvent) {
7412 if (aEvent.mMessage != eWheel) {
7413 return WheelDeltaAdjustmentStrategy::eNone;
7414 }
7415 switch (WheelPrefs::GetInstance()->ComputeActionFor(&aEvent)) {
7416 case WheelPrefs::ACTION_SCROLL:
7417 if (StaticPrefs::mousewheel_autodir_enabled() && 0 == aEvent.mDeltaZ) {
7418 if (StaticPrefs::mousewheel_autodir_honourroot()) {
7419 return WheelDeltaAdjustmentStrategy::eAutoDirWithRootHonour;
7420 }
7421 return WheelDeltaAdjustmentStrategy::eAutoDir;
7422 }
7423 return WheelDeltaAdjustmentStrategy::eNone;
7424 case WheelPrefs::ACTION_HORIZONTALIZED_SCROLL:
7425 return WheelDeltaAdjustmentStrategy::eHorizontalize;
7426 default:
7427 break;
7428 }
7429 return WheelDeltaAdjustmentStrategy::eNone;
7430}
7431
7432void EventStateManager::GetUserPrefsForWheelEvent(
7433 const WidgetWheelEvent* aEvent, double* aOutMultiplierX,
7434 double* aOutMultiplierY) {
7435 WheelPrefs::GetInstance()->GetUserPrefsForEvent(aEvent, aOutMultiplierX,
7436 aOutMultiplierY);
7437}
7438
7439bool EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedX(
7440 const WidgetWheelEvent* aEvent) {
7441 Index index = GetIndexFor(aEvent);
7442 Init(index);
7443 return Abs(mMultiplierX[index]) >=
7444 MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
7445}
7446
7447bool EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedY(
7448 const WidgetWheelEvent* aEvent) {
7449 Index index = GetIndexFor(aEvent);
7450 Init(index);
7451 return Abs(mMultiplierY[index]) >=
7452 MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
7453}
7454
7455} // namespace mozilla