Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp
Warning:line 5067, column 22
Called C++ object pointer is null

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-19/lib/clang/19 -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-19/lib/clang/19/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 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fno-sized-deallocation -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-09-22-115206-3586786-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 if (!StaticPrefs::dom_popup_experimental()) {
1021 NotifyTargetUserActivation(aEvent, aTargetContent);
1022 }
1023 break;
1024 }
1025 case eMouseUp: {
1026 switch (mouseEvent->mButton) {
1027 case MouseButton::ePrimary:
1028 if (StaticPrefs::ui_click_hold_context_menus()) {
1029 KillClickHoldTimer();
1030 }
1031 mInTouchDrag = false;
1032 StopTrackingDragGesture(true);
1033 sNormalLMouseEventInProcess = false;
1034 // then fall through...
1035 [[fallthrough]];
1036 case MouseButton::eSecondary:
1037 case MouseButton::eMiddle:
1038 RefPtr<EventStateManager> esm =
1039 ESMFromContentOrThis(aOverrideClickTarget);
1040 esm->SetClickCount(mouseEvent, aStatus, aOverrideClickTarget);
1041 break;
1042 }
1043 break;
1044 }
1045 case eMouseEnterIntoWidget:
1046 PointerEventHandler::UpdateActivePointerState(mouseEvent, aTargetContent);
1047 // In some cases on e10s eMouseEnterIntoWidget
1048 // event was sent twice into child process of content.
1049 // (From specific widget code (sending is not permanent) and
1050 // from ESM::DispatchMouseOrPointerBoundaryEvent (sending is permanent)).
1051 // IsCrossProcessForwardingStopped() helps to suppress sending accidental
1052 // event from widget code.
1053 aEvent->StopCrossProcessForwarding();
1054 break;
1055 case eMouseExitFromWidget:
1056 // If this is a remote frame, we receive eMouseExitFromWidget from the
1057 // parent the mouse exits our content. Since the parent may update the
1058 // cursor while the mouse is outside our frame, and since PuppetWidget
1059 // caches the current cursor internally, re-entering our content (say from
1060 // over a window edge) wont update the cursor if the cached value and the
1061 // current cursor match. So when the mouse exits a remote frame, clear the
1062 // cached widget cursor so a proper update will occur when the mouse
1063 // re-enters.
1064 if (XRE_IsContentProcess()) {
1065 ClearCachedWidgetCursor(mCurrentTarget);
1066 }
1067
1068 // IsCrossProcessForwardingStopped() helps to suppress double event
1069 // sending into process of content. For more information see comment
1070 // above, at eMouseEnterIntoWidget case.
1071 aEvent->StopCrossProcessForwarding();
1072
1073 // If the event is not a top-level window or puppet widget exit, then it's
1074 // not really an exit --- we may have traversed widget boundaries but
1075 // we're still in our toplevel window or puppet widget.
1076 if (mouseEvent->mExitFrom.value() !=
1077 WidgetMouseEvent::ePlatformTopLevel &&
1078 mouseEvent->mExitFrom.value() != WidgetMouseEvent::ePuppet) {
1079 // Treat it as a synthetic move so we don't generate spurious
1080 // "exit" or "move" events. Any necessary "out" or "over" events
1081 // will be generated by GenerateMouseEnterExit
1082 mouseEvent->mMessage = eMouseMove;
1083 mouseEvent->mReason = WidgetMouseEvent::eSynthesized;
1084 // then fall through...
1085 } else {
1086 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"
, 1088); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
")"); do { *((volatile int*)__null) = 1088; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1087 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"
, 1088); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
")"); do { *((volatile int*)__null) = 1088; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1088 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"
, 1088); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
")"); do { *((volatile int*)__null) = 1088; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1089 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"
, 1090); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
")"); do { *((volatile int*)__null) = 1090; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1090 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"
, 1090); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
")"); do { *((volatile int*)__null) = 1090; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1091 // We should synthetize corresponding pointer events
1092 GeneratePointerEnterExit(ePointerLeave, mouseEvent);
1093 GenerateMouseEnterExit(mouseEvent);
1094 // This is really an exit and should stop here
1095 aEvent->mMessage = eVoidEvent;
1096 break;
1097 }
1098 [[fallthrough]];
1099 case eMouseMove:
1100 case ePointerDown:
1101 if (aEvent->mMessage == ePointerDown) {
1102 PointerEventHandler::UpdateActivePointerState(mouseEvent,
1103 aTargetContent);
1104 PointerEventHandler::ImplicitlyCapturePointer(aTargetFrame, aEvent);
1105 if (StaticPrefs::dom_popup_experimental()) {
1106 // https://html.spec.whatwg.org/multipage/interaction.html#activation-triggering-input-event
1107 if (mouseEvent->mInputSource ==
1108 MouseEvent_Binding::MOZ_SOURCE_MOUSE) {
1109 NotifyTargetUserActivation(aEvent, aTargetContent);
1110 }
1111 } else if (mouseEvent->mInputSource !=
1112 MouseEvent_Binding::MOZ_SOURCE_TOUCH) {
1113 NotifyTargetUserActivation(aEvent, aTargetContent);
1114 }
1115
1116 LightDismissOpenPopovers(aEvent, aTargetContent);
1117 }
1118 [[fallthrough]];
1119 case ePointerMove: {
1120 if (!mInTouchDrag &&
1121 PointerEventHandler::IsDragAndDropEnabled(*mouseEvent)) {
1122 GenerateDragGesture(aPresContext, mouseEvent);
1123 }
1124 // on the Mac, GenerateDragGesture() may not return until the drag
1125 // has completed and so |aTargetFrame| may have been deleted (moving
1126 // a bookmark, for example). If this is the case, however, we know
1127 // that ClearFrameRefs() has been called and it cleared out
1128 // |mCurrentTarget|. As a result, we should pass |mCurrentTarget|
1129 // into UpdateCursor().
1130 UpdateCursor(aPresContext, mouseEvent, mCurrentTarget, aStatus);
1131
1132 UpdateLastRefPointOfMouseEvent(mouseEvent);
1133 if (PointerLockManager::IsLocked()) {
1134 ResetPointerToWindowCenterWhilePointerLocked(mouseEvent);
1135 }
1136 UpdateLastPointerPosition(mouseEvent);
1137
1138 GenerateMouseEnterExit(mouseEvent);
1139 // Flush pending layout changes, so that later mouse move events
1140 // will go to the right nodes.
1141 FlushLayout(aPresContext);
1142 break;
1143 }
1144 case ePointerUp:
1145 LightDismissOpenPopovers(aEvent, aTargetContent);
1146 GenerateMouseEnterExit(mouseEvent);
1147 if (StaticPrefs::dom_popup_experimental() &&
1148 mouseEvent->mInputSource != MouseEvent_Binding::MOZ_SOURCE_MOUSE) {
1149 NotifyTargetUserActivation(aEvent, aTargetContent);
1150 }
1151 break;
1152 case ePointerGotCapture:
1153 GenerateMouseEnterExit(mouseEvent);
1154 break;
1155 case eDragStart:
1156 if (StaticPrefs::ui_click_hold_context_menus()) {
1157 // an external drag gesture event came in, not generated internally
1158 // by Gecko. Make sure we get rid of the click-hold timer.
1159 KillClickHoldTimer();
1160 }
1161 break;
1162 case eDragOver: {
1163 WidgetDragEvent* dragEvent = aEvent->AsDragEvent();
1164 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"
, 1164); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dragEvent" ")"
); do { *((volatile int*)__null) = 1164; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1165 if (dragEvent->mFlags.mIsSynthesizedForTests &&
1166 allowSynthesisForTests()) {
1167 dragEvent->InitDropEffectForTests();
1168 }
1169 // Send the enter/exit events before eDrop.
1170 GenerateDragDropEnterExit(aPresContext, dragEvent);
1171 break;
1172 }
1173 case eDrop: {
1174 if (aEvent->mFlags.mIsSynthesizedForTests && allowSynthesisForTests()) {
1175 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"
, 1175); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->AsDragEvent()"
")"); do { *((volatile int*)__null) = 1175; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1176 aEvent->AsDragEvent()->InitDropEffectForTests();
1177 }
1178 break;
1179 }
1180 case eKeyPress: {
1181 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
1182 if (keyEvent->ModifiersMatchWithAccessKey(AccessKeyType::eChrome) ||
1183 keyEvent->ModifiersMatchWithAccessKey(AccessKeyType::eContent)) {
1184 // If the eKeyPress event will be sent to a remote process, this
1185 // process needs to wait reply from the remote process for checking if
1186 // preceding eKeyDown event is consumed. If preceding eKeyDown event
1187 // is consumed in the remote process, BrowserChild won't send the event
1188 // back to this process. So, only when this process receives a reply
1189 // eKeyPress event in BrowserParent, we should handle accesskey in this
1190 // process.
1191 if (IsTopLevelRemoteTarget(GetFocusedElement())) {
1192 // However, if there is no accesskey target for the key combination,
1193 // we don't need to wait reply from the remote process. Otherwise,
1194 // Mark the event as waiting reply from remote process and stop
1195 // propagation in this process.
1196 if (CheckIfEventMatchesAccessKey(keyEvent, aPresContext)) {
1197 keyEvent->StopPropagation();
1198 keyEvent->MarkAsWaitingReplyFromRemoteProcess();
1199 }
1200 }
1201 // If the event target is in this process, we can handle accesskey now
1202 // since if preceding eKeyDown event was consumed, eKeyPress event
1203 // won't be dispatched by widget. So, coming eKeyPress event means
1204 // that the preceding eKeyDown event wasn't consumed in this case.
1205 else {
1206 AutoTArray<uint32_t, 10> accessCharCodes;
1207 keyEvent->GetAccessKeyCandidates(accessCharCodes);
1208
1209 if (HandleAccessKey(keyEvent, aPresContext, accessCharCodes)) {
1210 *aStatus = nsEventStatus_eConsumeNoDefault;
1211 }
1212 }
1213 }
1214 }
1215 // then fall through...
1216 [[fallthrough]];
1217 case eKeyDown:
1218 if (aEvent->mMessage == eKeyDown) {
1219 NotifyTargetUserActivation(aEvent, aTargetContent);
1220 }
1221 [[fallthrough]];
1222 case eKeyUp: {
1223 Element* element = GetFocusedElement();
1224 if (element) {
1225 mCurrentTargetContent = element;
1226 }
1227
1228 // NOTE: Don't refer TextComposition::IsComposing() since UI Events
1229 // defines that KeyboardEvent.isComposing is true when it's
1230 // dispatched after compositionstart and compositionend.
1231 // TextComposition::IsComposing() is false even before
1232 // compositionend if there is no composing string.
1233 // And also don't expose other document's composition state.
1234 // A native IME context is typically shared by multiple documents.
1235 // So, don't use GetTextCompositionFor(nsIWidget*) here.
1236 RefPtr<TextComposition> composition =
1237 IMEStateManager::GetTextCompositionFor(aPresContext);
1238 aEvent->AsKeyboardEvent()->mIsComposing = !!composition;
1239
1240 // Widget may need to perform default action for specific keyboard
1241 // event if it's not consumed. In this case, widget has already marked
1242 // the event as "waiting reply from remote process". However, we need
1243 // to reset it if the target (focused content) isn't in a remote process
1244 // because PresShell needs to check if it's marked as so before
1245 // dispatching events into the DOM tree.
1246 if (aEvent->IsWaitingReplyFromRemoteProcess() &&
1247 !aEvent->PropagationStopped() && !IsTopLevelRemoteTarget(element)) {
1248 aEvent->ResetWaitingReplyFromRemoteProcessState();
1249 }
1250 } break;
1251 case eWheel:
1252 case eWheelOperationStart:
1253 case eWheelOperationEnd: {
1254 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"
, 1255); MOZ_PretendNoReturn(); } } while (0)
1255 "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"
, 1255); MOZ_PretendNoReturn(); } } while (0)
;
1256 using DeltaModeCheckingState = WidgetWheelEvent::DeltaModeCheckingState;
1257
1258 if (Element* element = GetFocusedElement()) {
1259 mCurrentTargetContent = element;
1260 }
1261
1262 if (aEvent->mMessage != eWheel) {
1263 break;
1264 }
1265
1266 WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
1267 WheelPrefs::GetInstance()->ApplyUserPrefsToDelta(wheelEvent);
1268
1269 // If we won't dispatch a DOM event for this event, nothing to do anymore.
1270 if (!wheelEvent->IsAllowedToDispatchDOMEvent()) {
1271 break;
1272 }
1273
1274 if (StaticPrefs::dom_event_wheel_deltaMode_lines_always_disabled()) {
1275 wheelEvent->mDeltaModeCheckingState = DeltaModeCheckingState::Unchecked;
1276 } else if (ShouldAlwaysUseLineDeltas()) {
1277 wheelEvent->mDeltaModeCheckingState = DeltaModeCheckingState::Checked;
1278 } else {
1279 wheelEvent->mDeltaModeCheckingState = DeltaModeCheckingState::Unknown;
1280 }
1281
1282 // Init lineOrPageDelta values for line scroll events for some devices
1283 // on some platforms which might dispatch wheel events which don't
1284 // have lineOrPageDelta values. And also, if delta values are
1285 // customized by prefs, this recomputes them.
1286 DeltaAccumulator::GetInstance()->InitLineOrPageDelta(aTargetFrame, this,
1287 wheelEvent);
1288 } break;
1289 case eSetSelection: {
1290 RefPtr<Element> focuedElement = GetFocusedElement();
1291 IMEStateManager::HandleSelectionEvent(aPresContext, focuedElement,
1292 aEvent->AsSelectionEvent());
1293 break;
1294 }
1295 case eContentCommandCut:
1296 case eContentCommandCopy:
1297 case eContentCommandPaste:
1298 case eContentCommandDelete:
1299 case eContentCommandUndo:
1300 case eContentCommandRedo:
1301 case eContentCommandPasteTransferable:
1302 case eContentCommandLookUpDictionary:
1303 DoContentCommandEvent(aEvent->AsContentCommandEvent());
1304 break;
1305 case eContentCommandInsertText:
1306 DoContentCommandInsertTextEvent(aEvent->AsContentCommandEvent());
1307 break;
1308 case eContentCommandReplaceText:
1309 DoContentCommandReplaceTextEvent(aEvent->AsContentCommandEvent());
1310 break;
1311 case eContentCommandScroll:
1312 DoContentCommandScrollEvent(aEvent->AsContentCommandEvent());
1313 break;
1314 case eCompositionStart:
1315 if (aEvent->IsTrusted()) {
1316 // If the event is trusted event, set the selected text to data of
1317 // composition event.
1318 WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent();
1319 WidgetQueryContentEvent querySelectedTextEvent(
1320 true, eQuerySelectedText, compositionEvent->mWidget);
1321 HandleQueryContentEvent(&querySelectedTextEvent);
1322 if (querySelectedTextEvent.FoundSelection()) {
1323 compositionEvent->mData = querySelectedTextEvent.mReply->DataRef();
1324 }
1325 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"
, 1326); MOZ_PretendNoReturn(); } } while (0)
1326 "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"
, 1326); MOZ_PretendNoReturn(); } } while (0)
;
1327 }
1328 break;
1329 case eTouchStart:
1330 SetGestureDownPoint(aEvent->AsTouchEvent());
1331 break;
1332 case eTouchEnd:
1333 if (!StaticPrefs::dom_popup_experimental()) {
1334 NotifyTargetUserActivation(aEvent, aTargetContent);
1335 }
1336 break;
1337 default:
1338 break;
1339 }
1340 return NS_OK;
1341}
1342
1343// Returns true if this event is likely an user activation for a link or
1344// a link-like button, where modifier keys are likely be used for controlling
1345// where the link is opened.
1346//
1347// The modifiers associated with the user activation is used for controlling
1348// where the `window.open` is opened into.
1349static bool CanReflectModifiersToUserActivation(WidgetInputEvent* aEvent) {
1350 if (StaticPrefs::dom_popup_experimental()) {
1351 MOZ_ASSERT(aEvent->mMessage == eKeyDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1353); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1353; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1352 aEvent->mMessage == ePointerDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1353); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1353; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1353 aEvent->mMessage == ePointerUp)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1353); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1353; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1354 } else {
1355 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"
, 1357); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1357; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1356 aEvent->mMessage == ePointerDown ||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"
, 1357); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1357; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1357 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"
, 1357); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1357; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1358 }
1359
1360 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
1361 if (keyEvent) {
1362 return keyEvent->CanReflectModifiersToUserActivation();
1363 }
1364
1365 return true;
1366}
1367
1368void EventStateManager::NotifyTargetUserActivation(WidgetEvent* aEvent,
1369 nsIContent* aTargetContent) {
1370 if (!aEvent->IsTrusted()) {
1371 return;
1372 }
1373
1374 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
1375 if (mouseEvent && !mouseEvent->IsReal()) {
1376 return;
1377 }
1378
1379 nsCOMPtr<nsINode> node = aTargetContent;
1380 if (!node) {
1381 return;
1382 }
1383
1384 Document* doc = node->OwnerDoc();
1385 if (!doc) {
1386 return;
1387 }
1388
1389 // Don't gesture activate for key events for keys which are likely
1390 // to be interaction with the browser, OS.
1391 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
1392 if (keyEvent && !keyEvent->CanUserGestureActivateTarget()) {
1393 return;
1394 }
1395
1396 // Touch gestures that end outside the drag target were touches that turned
1397 // into scroll/pan/swipe actions. We don't want to gesture activate on such
1398 // actions, we want to only gesture activate on touches that are taps.
1399 // That is, touches that end in roughly the same place that they started.
1400 if ((aEvent->mMessage == eTouchEnd ||
1401 (aEvent->mMessage == ePointerUp &&
1402 aEvent->AsPointerEvent()->mInputSource ==
1403 MouseEvent_Binding::MOZ_SOURCE_TOUCH)) &&
1404 IsEventOutsideDragThreshold(aEvent->AsInputEvent())) {
1405 return;
1406 }
1407
1408 // Do not treat the click on scrollbar as a user interaction with the web
1409 // content.
1410 if (StaticPrefs::dom_user_activation_ignore_scrollbars() &&
1411 ((StaticPrefs::dom_popup_experimental() &&
1412 (aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp)) ||
1413 (!StaticPrefs::dom_popup_experimental() &&
1414 (aEvent->mMessage == eMouseDown ||
1415 aEvent->mMessage == ePointerDown))) &&
1416 aTargetContent->IsInNativeAnonymousSubtree()) {
1417 nsIContent* current = aTargetContent;
1418 do {
1419 nsIContent* root = current->GetClosestNativeAnonymousSubtreeRoot();
1420 if (!root) {
1421 break;
1422 }
1423 if (root->IsXULElement(nsGkAtoms::scrollbar)) {
1424 return;
1425 }
1426 current = root->GetParent();
1427 } while (current);
1428 }
1429
1430#ifdef DEBUG1
1431 if (StaticPrefs::dom_popup_experimental()) {
1432 MOZ_ASSERT(aEvent->mMessage == eKeyDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1434); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1434; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1433 aEvent->mMessage == ePointerDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1434); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1434; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1434 aEvent->mMessage == ePointerUp)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1434); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1434; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1435 } else {
1436 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"
, 1438); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1438; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1437 aEvent->mMessage == ePointerDown ||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"
, 1438); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1438; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1438 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"
, 1438); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1438; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1439 }
1440#endif
1441
1442 UserActivation::Modifiers modifiers;
1443 if (WidgetInputEvent* inputEvent = aEvent->AsInputEvent()) {
1444 if (CanReflectModifiersToUserActivation(inputEvent)) {
1445 if (inputEvent->IsShift()) {
1446 modifiers.SetShift();
1447 }
1448 if (inputEvent->IsMeta()) {
1449 modifiers.SetMeta();
1450 }
1451 if (inputEvent->IsControl()) {
1452 modifiers.SetControl();
1453 }
1454 if (inputEvent->IsAlt()) {
1455 modifiers.SetAlt();
1456 }
1457
1458 WidgetMouseEvent* mouseEvent = inputEvent->AsMouseEvent();
1459 if (mouseEvent) {
1460 if (mouseEvent->mButton == MouseButton::eMiddle) {
1461 modifiers.SetMiddleMouse();
1462 }
1463 }
1464 }
1465 }
1466 doc->NotifyUserGestureActivation(modifiers);
1467}
1468
1469// https://html.spec.whatwg.org/multipage/popover.html#popover-light-dismiss
1470void EventStateManager::LightDismissOpenPopovers(WidgetEvent* aEvent,
1471 nsIContent* aTargetContent) {
1472 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"
, 1473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
") (" "Light dismiss must be called for pointer up/down only"
")"); do { *((volatile int*)__null) = 1473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1473 "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"
, 1473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
") (" "Light dismiss must be called for pointer up/down only"
")"); do { *((volatile int*)__null) = 1473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1474
1475 if (!StaticPrefs::dom_element_popover_enabled() || !aEvent->IsTrusted() ||
1476 !aTargetContent) {
1477 return;
1478 }
1479
1480 Element* topmostPopover = aTargetContent->OwnerDoc()->GetTopmostAutoPopover();
1481 if (!topmostPopover) {
1482 return;
1483 }
1484
1485 // Pointerdown: set document's popover pointerdown target to the result of
1486 // running topmost clicked popover given target.
1487 if (aEvent->mMessage == ePointerDown) {
1488 mPopoverPointerDownTarget = aTargetContent->GetTopmostClickedPopover();
1489 return;
1490 }
1491
1492 // Pointerup: hide open popovers.
1493 RefPtr<nsINode> ancestor = aTargetContent->GetTopmostClickedPopover();
1494 bool sameTarget = mPopoverPointerDownTarget == ancestor;
1495 mPopoverPointerDownTarget = nullptr;
1496 if (!sameTarget) {
1497 return;
1498 }
1499
1500 if (!ancestor) {
1501 ancestor = aTargetContent->OwnerDoc();
1502 }
1503 RefPtr<Document> doc(ancestor->OwnerDoc());
1504 doc->HideAllPopoversUntil(*ancestor, false, true);
1505}
1506
1507already_AddRefed<EventStateManager> EventStateManager::ESMFromContentOrThis(
1508 nsIContent* aContent) {
1509 if (aContent) {
1510 PresShell* presShell = aContent->OwnerDoc()->GetPresShell();
1511 if (presShell) {
1512 nsPresContext* prescontext = presShell->GetPresContext();
1513 if (prescontext) {
1514 RefPtr<EventStateManager> esm = prescontext->EventStateManager();
1515 if (esm) {
1516 return esm.forget();
1517 }
1518 }
1519 }
1520 }
1521
1522 RefPtr<EventStateManager> esm = this;
1523 return esm.forget();
1524}
1525
1526EventStateManager::LastMouseDownInfo& EventStateManager::GetLastMouseDownInfo(
1527 int16_t aButton) {
1528 switch (aButton) {
1529 case MouseButton::ePrimary:
1530 return mLastLeftMouseDownInfo;
1531 case MouseButton::eMiddle:
1532 return mLastMiddleMouseDownInfo;
1533 case MouseButton::eSecondary:
1534 return mLastRightMouseDownInfo;
1535 default:
1536 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"
, 1536); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "This button shouldn't use this method"
")"); do { *((volatile int*)__null) = 1536; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1537 return mLastLeftMouseDownInfo;
1538 }
1539}
1540
1541void EventStateManager::HandleQueryContentEvent(
1542 WidgetQueryContentEvent* aEvent) {
1543 switch (aEvent->mMessage) {
1544 case eQuerySelectedText:
1545 case eQueryTextContent:
1546 case eQueryCaretRect:
1547 case eQueryTextRect:
1548 case eQueryEditorRect:
1549 if (!IsTargetCrossProcess(aEvent)) {
1550 break;
1551 }
1552 // Will not be handled locally, remote the event
1553 GetCrossProcessTarget()->HandleQueryContentEvent(*aEvent);
1554 return;
1555 // Following events have not been supported in e10s mode yet.
1556 case eQueryContentState:
1557 case eQuerySelectionAsTransferable:
1558 case eQueryCharacterAtPoint:
1559 case eQueryDOMWidgetHittest:
1560 case eQueryTextRectArray:
1561 case eQueryDropTargetHittest:
1562 break;
1563 default:
1564 return;
1565 }
1566
1567 // If there is an IMEContentObserver, we need to handle QueryContentEvent
1568 // with it.
1569 // eQueryDropTargetHittest is not really an IME event, though
1570 if (mIMEContentObserver && aEvent->mMessage != eQueryDropTargetHittest) {
1571 RefPtr<IMEContentObserver> contentObserver = mIMEContentObserver;
1572 contentObserver->HandleQueryContentEvent(aEvent);
1573 return;
1574 }
1575
1576 ContentEventHandler handler(mPresContext);
1577 handler.HandleQueryContentEvent(aEvent);
1578}
1579
1580static AccessKeyType GetAccessKeyTypeFor(nsISupports* aDocShell) {
1581 nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(aDocShell));
1582 if (!treeItem) {
1583 return AccessKeyType::eNone;
1584 }
1585
1586 switch (treeItem->ItemType()) {
1587 case nsIDocShellTreeItem::typeChrome:
1588 return AccessKeyType::eChrome;
1589 case nsIDocShellTreeItem::typeContent:
1590 return AccessKeyType::eContent;
1591 default:
1592 return AccessKeyType::eNone;
1593 }
1594}
1595
1596static bool IsAccessKeyTarget(Element* aElement, nsAString& aKey) {
1597 // Use GetAttr because we want Unicode case=insensitive matching
1598 // XXXbz shouldn't this be case-sensitive, per spec?
1599 nsString contentKey;
1600 if (!aElement || !aElement->GetAttr(nsGkAtoms::accesskey, contentKey) ||
1601 !contentKey.Equals(aKey, nsCaseInsensitiveStringComparator)) {
1602 return false;
1603 }
1604
1605 if (!aElement->IsXULElement()) {
1606 return true;
1607 }
1608
1609 // For XUL we do visibility checks.
1610 nsIFrame* frame = aElement->GetPrimaryFrame();
1611 if (!frame) {
1612 return false;
1613 }
1614
1615 if (frame->IsFocusable()) {
1616 return true;
1617 }
1618
1619 if (!frame->IsVisibleConsideringAncestors()) {
1620 return false;
1621 }
1622
1623 // XUL controls can be activated.
1624 nsCOMPtr<nsIDOMXULControlElement> control = aElement->AsXULControl();
1625 if (control) {
1626 return true;
1627 }
1628
1629 // XUL label elements are never focusable, so we need to check for them
1630 // explicitly before giving up.
1631 if (aElement->IsXULElement(nsGkAtoms::label)) {
1632 return true;
1633 }
1634
1635 return false;
1636}
1637
1638bool EventStateManager::CheckIfEventMatchesAccessKey(
1639 WidgetKeyboardEvent* aEvent, nsPresContext* aPresContext) {
1640 AutoTArray<uint32_t, 10> accessCharCodes;
1641 aEvent->GetAccessKeyCandidates(accessCharCodes);
1642 return WalkESMTreeToHandleAccessKey(aEvent, aPresContext, accessCharCodes,
1643 nullptr, eAccessKeyProcessingNormal,
1644 false);
1645}
1646
1647bool EventStateManager::LookForAccessKeyAndExecute(
1648 nsTArray<uint32_t>& aAccessCharCodes, bool aIsTrustedEvent, bool aIsRepeat,
1649 bool aExecute) {
1650 int32_t count, start = -1;
1651 if (Element* focusedElement = GetFocusedElement()) {
1652 start = mAccessKeys.IndexOf(focusedElement);
1653 if (start == -1 && focusedElement->IsInNativeAnonymousSubtree()) {
1654 start = mAccessKeys.IndexOf(Element::FromNodeOrNull(
1655 focusedElement->GetClosestNativeAnonymousSubtreeRootParentOrHost()));
1656 }
1657 }
1658 RefPtr<Element> element;
1659 int32_t length = mAccessKeys.Count();
1660 for (uint32_t i = 0; i < aAccessCharCodes.Length(); ++i) {
1661 uint32_t ch = aAccessCharCodes[i];
1662 nsAutoString accessKey;
1663 AppendUCS4ToUTF16(ch, accessKey);
1664 for (count = 1; count <= length; ++count) {
1665 // mAccessKeys always stores Element instances.
1666 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"
, 1666); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "length == mAccessKeys.Count()"
")"); do { *((volatile int*)__null) = 1666; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1667 element = mAccessKeys[(start + count) % length];
1668 if (IsAccessKeyTarget(element, accessKey)) {
1669 if (!aExecute) {
1670 return true;
1671 }
1672 Document* doc = element->OwnerDoc();
1673 const bool shouldActivate = [&] {
1674 if (!StaticPrefs::accessibility_accesskeycausesactivation()) {
1675 return false;
1676 }
1677 if (aIsRepeat && nsContentUtils::IsChromeDoc(doc)) {
1678 return false;
1679 }
1680
1681 // XXXedgar, Bug 1700646, maybe we could use other data structure to
1682 // make searching target with same accesskey easier, and current setup
1683 // could not ensure we cycle the target with tree order.
1684 int32_t j = 0;
1685 while (++j < length) {
1686 Element* el = mAccessKeys[(start + count + j) % length];
1687 if (IsAccessKeyTarget(el, accessKey)) {
1688 return false;
1689 }
1690 }
1691 return true;
1692 }();
1693
1694 // TODO(bug 1641171): This shouldn't be needed if we considered the
1695 // accesskey combination properly.
1696 if (aIsTrustedEvent) {
1697 doc->NotifyUserGestureActivation();
1698 }
1699
1700 auto result =
1701 element->PerformAccesskey(shouldActivate, aIsTrustedEvent);
1702 if (result.isOk()) {
1703 if (result.unwrap() && aIsTrustedEvent) {
1704 // If this is a child process, inform the parent that we want the
1705 // focus, but pass false since we don't want to change the window
1706 // order.
1707 nsIDocShell* docShell = mPresContext->GetDocShell();
1708 nsCOMPtr<nsIBrowserChild> child =
1709 docShell ? docShell->GetBrowserChild() : nullptr;
1710 if (child) {
1711 child->SendRequestFocus(false, CallerType::System);
1712 }
1713 }
1714 return true;
1715 }
1716 }
1717 }
1718 }
1719 return false;
1720}
1721
1722// static
1723void EventStateManager::GetAccessKeyLabelPrefix(Element* aElement,
1724 nsAString& aPrefix) {
1725 aPrefix.Truncate();
1726 nsAutoString separator, modifierText;
1727 nsContentUtils::GetModifierSeparatorText(separator);
1728
1729 AccessKeyType accessKeyType =
1730 GetAccessKeyTypeFor(aElement->OwnerDoc()->GetDocShell());
1731 if (accessKeyType == AccessKeyType::eNone) {
1732 return;
1733 }
1734 Modifiers modifiers = WidgetKeyboardEvent::AccessKeyModifiers(accessKeyType);
1735 if (modifiers == MODIFIER_NONE) {
1736 return;
1737 }
1738
1739 if (modifiers & MODIFIER_CONTROL) {
1740 nsContentUtils::GetControlText(modifierText);
1741 aPrefix.Append(modifierText + separator);
1742 }
1743 if (modifiers & MODIFIER_META) {
1744 nsContentUtils::GetCommandOrWinText(modifierText);
1745 aPrefix.Append(modifierText + separator);
1746 }
1747 if (modifiers & MODIFIER_ALT) {
1748 nsContentUtils::GetAltText(modifierText);
1749 aPrefix.Append(modifierText + separator);
1750 }
1751 if (modifiers & MODIFIER_SHIFT) {
1752 nsContentUtils::GetShiftText(modifierText);
1753 aPrefix.Append(modifierText + separator);
1754 }
1755}
1756
1757struct MOZ_STACK_CLASS AccessKeyInfo {
1758 WidgetKeyboardEvent* event;
1759 nsTArray<uint32_t>& charCodes;
1760
1761 AccessKeyInfo(WidgetKeyboardEvent* aEvent, nsTArray<uint32_t>& aCharCodes)
1762 : event(aEvent), charCodes(aCharCodes) {}
1763};
1764
1765bool EventStateManager::WalkESMTreeToHandleAccessKey(
1766 WidgetKeyboardEvent* aEvent, nsPresContext* aPresContext,
1767 nsTArray<uint32_t>& aAccessCharCodes, nsIDocShellTreeItem* aBubbledFrom,
1768 ProcessingAccessKeyState aAccessKeyState, bool aExecute) {
1769 EnsureDocument(mPresContext);
1770 nsCOMPtr<nsIDocShell> docShell = aPresContext->GetDocShell();
1771 if (NS_WARN_IF(!docShell)NS_warn_if_impl(!docShell, "!docShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1771)
|| NS_WARN_IF(!mDocument)NS_warn_if_impl(!mDocument, "!mDocument", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1771)
) {
1772 return false;
1773 }
1774 AccessKeyType accessKeyType = GetAccessKeyTypeFor(docShell);
1775 if (accessKeyType == AccessKeyType::eNone) {
1776 return false;
1777 }
1778 // Alt or other accesskey modifier is down, we may need to do an accesskey.
1779 if (mAccessKeys.Count() > 0 &&
1780 aEvent->ModifiersMatchWithAccessKey(accessKeyType)) {
1781 // Someone registered an accesskey. Find and activate it.
1782 if (LookForAccessKeyAndExecute(aAccessCharCodes, aEvent->IsTrusted(),
1783 aEvent->mIsRepeat, aExecute)) {
1784 return true;
1785 }
1786 }
1787
1788 int32_t childCount;
1789 docShell->GetInProcessChildCount(&childCount);
1790 for (int32_t counter = 0; counter < childCount; counter++) {
1791 // Not processing the child which bubbles up the handling
1792 nsCOMPtr<nsIDocShellTreeItem> subShellItem;
1793 docShell->GetInProcessChildAt(counter, getter_AddRefs(subShellItem));
1794 if (aAccessKeyState == eAccessKeyProcessingUp &&
1795 subShellItem == aBubbledFrom) {
1796 continue;
1797 }
1798
1799 nsCOMPtr<nsIDocShell> subDS = do_QueryInterface(subShellItem);
1800 if (subDS && IsShellVisible(subDS)) {
1801 // Guarantee subPresShell lifetime while we're handling access key
1802 // since somebody may assume that it won't be deleted before the
1803 // corresponding nsPresContext and EventStateManager.
1804 RefPtr<PresShell> subPresShell = subDS->GetPresShell();
1805
1806 // Docshells need not have a presshell (eg. display:none
1807 // iframes, docshells in transition between documents, etc).
1808 if (!subPresShell) {
1809 // Oh, well. Just move on to the next child
1810 continue;
1811 }
1812
1813 RefPtr<nsPresContext> subPresContext = subPresShell->GetPresContext();
1814
1815 RefPtr<EventStateManager> esm =
1816 static_cast<EventStateManager*>(subPresContext->EventStateManager());
1817
1818 if (esm && esm->WalkESMTreeToHandleAccessKey(
1819 aEvent, subPresContext, aAccessCharCodes, nullptr,
1820 eAccessKeyProcessingDown, aExecute)) {
1821 return true;
1822 }
1823 }
1824 } // if end . checking all sub docshell ends here.
1825
1826 // bubble up the process to the parent docshell if necessary
1827 if (eAccessKeyProcessingDown != aAccessKeyState) {
1828 nsCOMPtr<nsIDocShellTreeItem> parentShellItem;
1829 docShell->GetInProcessParent(getter_AddRefs(parentShellItem));
1830 nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parentShellItem);
1831 if (parentDS) {
1832 // Guarantee parentPresShell lifetime while we're handling access key
1833 // since somebody may assume that it won't be deleted before the
1834 // corresponding nsPresContext and EventStateManager.
1835 RefPtr<PresShell> parentPresShell = parentDS->GetPresShell();
1836 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"
, 1837); MOZ_PretendNoReturn(); } } while (0)
1837 "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"
, 1837); MOZ_PretendNoReturn(); } } while (0)
;
1838
1839 RefPtr<nsPresContext> parentPresContext =
1840 parentPresShell->GetPresContext();
1841 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"
, 1841); MOZ_PretendNoReturn(); } } while (0)
;
1842
1843 RefPtr<EventStateManager> esm = static_cast<EventStateManager*>(
1844 parentPresContext->EventStateManager());
1845 if (esm && esm->WalkESMTreeToHandleAccessKey(
1846 aEvent, parentPresContext, aAccessCharCodes, docShell,
1847 eAccessKeyProcessingDown, aExecute)) {
1848 return true;
1849 }
1850 }
1851 } // if end. bubble up process
1852
1853 // If the content access key modifier is pressed, try remote children
1854 if (aExecute &&
1855 aEvent->ModifiersMatchWithAccessKey(AccessKeyType::eContent) &&
1856 mDocument && mDocument->GetWindow()) {
1857 // If the focus is currently on a node with a BrowserParent, the key event
1858 // should've gotten forwarded to the child process and HandleAccessKey
1859 // called from there.
1860 if (BrowserParent::GetFrom(GetFocusedElement())) {
1861 // If access key may be only in remote contents, this method won't handle
1862 // access key synchronously. In this case, only reply event should reach
1863 // here.
1864 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"
, 1865); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsHandledInRemoteProcess() || !aEvent->IsWaitingReplyFromRemoteProcess()"
")"); do { *((volatile int*)__null) = 1865; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1865 !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"
, 1865); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsHandledInRemoteProcess() || !aEvent->IsWaitingReplyFromRemoteProcess()"
")"); do { *((volatile int*)__null) = 1865; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1866 }
1867 // If focus is somewhere else, then we need to check the remote children.
1868 // However, if the event has already been handled in a remote process,
1869 // then, focus is moved from the remote process after posting the event.
1870 // In such case, we shouldn't retry to handle access keys in remote
1871 // processes.
1872 else if (!aEvent->IsHandledInRemoteProcess()) {
1873 AccessKeyInfo accessKeyInfo(aEvent, aAccessCharCodes);
1874 nsContentUtils::CallOnAllRemoteChildren(
1875 mDocument->GetWindow(),
1876 [&accessKeyInfo](BrowserParent* aBrowserParent) -> CallState {
1877 // Only forward accesskeys for the active tab.
1878 if (aBrowserParent->GetDocShellIsActive()) {
1879 // Even if there is no target for the accesskey in this process,
1880 // the event may match with a content accesskey. If so, the
1881 // keyboard event should be handled with reply event for
1882 // preventing double action. (e.g., Alt+Shift+F on Windows may
1883 // focus a content in remote and open "File" menu.)
1884 accessKeyInfo.event->StopPropagation();
1885 accessKeyInfo.event->MarkAsWaitingReplyFromRemoteProcess();
1886 aBrowserParent->HandleAccessKey(*accessKeyInfo.event,
1887 accessKeyInfo.charCodes);
1888 return CallState::Stop;
1889 }
1890
1891 return CallState::Continue;
1892 });
1893 }
1894 }
1895
1896 return false;
1897} // end of HandleAccessKey
1898
1899static BrowserParent* GetBrowserParentAncestor(BrowserParent* aBrowserParent) {
1900 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"
, 1900); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aBrowserParent"
")"); do { *((volatile int*)__null) = 1900; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1901
1902 BrowserBridgeParent* bbp = aBrowserParent->GetBrowserBridgeParent();
1903 if (!bbp) {
1904 return nullptr;
1905 }
1906
1907 return bbp->Manager();
1908}
1909
1910static void DispatchCrossProcessMouseExitEvents(WidgetMouseEvent* aMouseEvent,
1911 BrowserParent* aRemoteTarget,
1912 BrowserParent* aStopAncestor,
1913 bool aIsReallyExit) {
1914 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"
, 1914); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseEvent"
")"); do { *((volatile int*)__null) = 1914; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1915 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"
, 1915); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRemoteTarget"
")"); do { *((volatile int*)__null) = 1915; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1916 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"
, 1916); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRemoteTarget != aStopAncestor"
")"); do { *((volatile int*)__null) = 1916; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1917 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"
, 1918); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::GetCommonBrowserParentAncestor( aRemoteTarget, aStopAncestor)"
")"); do { *((volatile int*)__null) = 1918; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1918 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"
, 1918); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::GetCommonBrowserParentAncestor( aRemoteTarget, aStopAncestor)"
")"); do { *((volatile int*)__null) = 1918; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1919
1920 while (aRemoteTarget != aStopAncestor) {
1921 UniquePtr<WidgetMouseEvent> mouseExitEvent =
1922 CreateMouseOrPointerWidgetEvent(aMouseEvent, eMouseExitFromWidget,
1923 aMouseEvent->mRelatedTarget);
1924 mouseExitEvent->mExitFrom =
1925 Some(aIsReallyExit ? WidgetMouseEvent::ePuppet
1926 : WidgetMouseEvent::ePuppetParentToPuppetChild);
1927 aRemoteTarget->SendRealMouseEvent(*mouseExitEvent);
1928
1929 aRemoteTarget = GetBrowserParentAncestor(aRemoteTarget);
1930 }
1931}
1932
1933void EventStateManager::DispatchCrossProcessEvent(WidgetEvent* aEvent,
1934 BrowserParent* aRemoteTarget,
1935 nsEventStatus* aStatus) {
1936 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"
, 1936); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 1936; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1937 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"
, 1937); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRemoteTarget"
")"); do { *((volatile int*)__null) = 1937; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1938 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"
, 1938); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 1938; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1939
1940 BrowserParent* remote = aRemoteTarget;
1941
1942 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
1943 bool isContextMenuKey = mouseEvent && mouseEvent->IsContextMenuKeyEvent();
1944 if (aEvent->mClass == eKeyboardEventClass || isContextMenuKey) {
1945 // APZ attaches a LayersId to hit-testable events, for keyboard events,
1946 // we use focus.
1947 BrowserParent* preciseRemote = BrowserParent::GetFocused();
1948 if (preciseRemote) {
1949 remote = preciseRemote;
1950 }
1951 // else there is a race between layout and focus tracking,
1952 // so fall back to delivering the event to the topmost child process.
1953 } else if (aEvent->mLayersId.IsValid()) {
1954 BrowserParent* preciseRemote =
1955 BrowserParent::GetBrowserParentFromLayersId(aEvent->mLayersId);
1956 if (preciseRemote) {
1957 remote = preciseRemote;
1958 }
1959 // else there is a race between APZ and the LayersId to BrowserParent
1960 // mapping, so fall back to delivering the event to the topmost child
1961 // process.
1962 }
1963
1964 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"
, 1964); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage != ePointerClick"
")"); do { *((volatile int*)__null) = 1964; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1965 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"
, 1965); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage != ePointerAuxClick"
")"); do { *((volatile int*)__null) = 1965; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1966
1967 // SendReal* will transform the coordinate to the child process coordinate
1968 // space. So restore the coordinate after the event has been dispatched to the
1969 // child process to avoid using the transformed coordinate afterward.
1970 AutoRestore<LayoutDeviceIntPoint> restore(aEvent->mRefPoint);
1971 switch (aEvent->mClass) {
1972 case ePointerEventClass:
1973 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"
, 1973); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eContextMenu"
")"); do { *((volatile int*)__null) = 1973; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1974 [[fallthrough]];
1975 case eMouseEventClass: {
1976 BrowserParent* oldRemote = BrowserParent::GetLastMouseRemoteTarget();
1977
1978 // If this is a eMouseExitFromWidget event, need to redirect the event to
1979 // the last remote and and notify all its ancestors about the exit, if
1980 // any.
1981 if (mouseEvent->mMessage == eMouseExitFromWidget) {
1982 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"
, 1982); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
")"); do { *((volatile int*)__null) = 1982; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1983 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"
, 1983); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mReason == WidgetMouseEvent::eReal"
")"); do { *((volatile int*)__null) = 1983; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1984 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"
, 1984); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mouseEvent->mLayersId.IsValid()"
")"); do { *((volatile int*)__null) = 1984; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1985 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"
, 1985); AnnotateMozCrashReason("MOZ_ASSERT" "(" "remote->GetBrowserHost()"
")"); do { *((volatile int*)__null) = 1985; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1986
1987 if (oldRemote && oldRemote != remote) {
1988 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"
, 1989)
1989 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"
, 1989)
;
1990 remote = oldRemote;
1991 }
1992
1993 DispatchCrossProcessMouseExitEvents(mouseEvent, remote, nullptr, true);
1994 return;
1995 }
1996
1997 if (BrowserParent* pointerLockedRemote =
1998 PointerLockManager::GetLockedRemoteTarget()) {
1999 remote = pointerLockedRemote;
2000 } else if (BrowserParent* pointerCapturedRemote =
2001 PointerEventHandler::GetPointerCapturingRemoteTarget(
2002 mouseEvent->pointerId)) {
2003 remote = pointerCapturedRemote;
2004 } else if (BrowserParent* capturingRemote =
2005 PresShell::GetCapturingRemoteTarget()) {
2006 remote = capturingRemote;
2007 }
2008
2009 // If a mouse is over a remote target A, and then moves to
2010 // remote target B, we'd deliver the event directly to remote target B
2011 // after the moving, A would never get notified that the mouse left.
2012 // So we generate a exit event to notify A after the move.
2013 // XXXedgar, if the synthesized mouse events could deliver to the correct
2014 // process directly (see
2015 // https://bugzilla.mozilla.org/show_bug.cgi?id=1549355), we probably
2016 // don't need to check mReason then.
2017 if (mouseEvent->mReason == WidgetMouseEvent::eReal &&
2018 remote != oldRemote) {
2019 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"
, 2019); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mMessage != eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 2019; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2020 if (oldRemote) {
2021 BrowserParent* commonAncestor =
2022 nsContentUtils::GetCommonBrowserParentAncestor(remote, oldRemote);
2023 if (commonAncestor == oldRemote) {
2024 // Mouse moves to the inner OOP frame, it is not a really exit.
2025 DispatchCrossProcessMouseExitEvents(
2026 mouseEvent, GetBrowserParentAncestor(remote),
2027 GetBrowserParentAncestor(commonAncestor), false);
2028 } else if (commonAncestor == remote) {
2029 // Mouse moves to the outer OOP frame, it is a really exit.
2030 DispatchCrossProcessMouseExitEvents(mouseEvent, oldRemote,
2031 commonAncestor, true);
2032 } else {
2033 // Mouse moves to OOP frame in other subtree, it is a really exit,
2034 // need to notify all its ancestors before common ancestor about the
2035 // exit.
2036 DispatchCrossProcessMouseExitEvents(mouseEvent, oldRemote,
2037 commonAncestor, true);
2038 if (commonAncestor) {
2039 UniquePtr<WidgetMouseEvent> mouseExitEvent =
2040 CreateMouseOrPointerWidgetEvent(mouseEvent,
2041 eMouseExitFromWidget,
2042 mouseEvent->mRelatedTarget);
2043 mouseExitEvent->mExitFrom =
2044 Some(WidgetMouseEvent::ePuppetParentToPuppetChild);
2045 commonAncestor->SendRealMouseEvent(*mouseExitEvent);
2046 }
2047 }
2048 }
2049
2050 if (mouseEvent->mMessage != eMouseExitFromWidget &&
2051 mouseEvent->mMessage != eMouseEnterIntoWidget) {
2052 // This is to make cursor would be updated correctly.
2053 remote->MouseEnterIntoWidget();
2054 }
2055 }
2056
2057 remote->SendRealMouseEvent(*mouseEvent);
2058 return;
2059 }
2060 case eKeyboardEventClass: {
2061 auto* keyboardEvent = aEvent->AsKeyboardEvent();
2062 if (aEvent->mMessage == eKeyUp) {
2063 HandleKeyUpInteraction(keyboardEvent);
2064 }
2065 remote->SendRealKeyEvent(*keyboardEvent);
2066 return;
2067 }
2068 case eWheelEventClass: {
2069 if (BrowserParent* pointerLockedRemote =
2070 PointerLockManager::GetLockedRemoteTarget()) {
2071 remote = pointerLockedRemote;
2072 }
2073 remote->SendMouseWheelEvent(*aEvent->AsWheelEvent());
2074 return;
2075 }
2076 case eTouchEventClass: {
2077 // Let the child process synthesize a mouse event if needed, and
2078 // ensure we don't synthesize one in this process.
2079 *aStatus = nsEventStatus_eConsumeNoDefault;
2080 remote->SendRealTouchEvent(*aEvent->AsTouchEvent());
2081 return;
2082 }
2083 case eDragEventClass: {
2084 RefPtr<BrowserParent> browserParent = remote;
2085 browserParent->MaybeInvokeDragSession(aEvent->mMessage);
2086
2087 RefPtr<nsIWidget> widget = browserParent->GetTopLevelWidget();
2088 nsCOMPtr<nsIDragSession> dragSession =
2089 nsContentUtils::GetDragSession(widget);
2090 uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
2091 uint32_t action = nsIDragService::DRAGDROP_ACTION_NONE;
2092 nsCOMPtr<nsIPrincipal> principal;
2093 nsCOMPtr<nsIContentSecurityPolicy> csp;
2094
2095 if (dragSession) {
2096 dragSession->DragEventDispatchedToChildProcess();
2097 dragSession->GetDragAction(&action);
2098 dragSession->GetTriggeringPrincipal(getter_AddRefs(principal));
2099 dragSession->GetCsp(getter_AddRefs(csp));
2100 RefPtr<DataTransfer> initialDataTransfer =
2101 dragSession->GetDataTransfer();
2102 if (initialDataTransfer) {
2103 dropEffect = initialDataTransfer->DropEffectInt();
2104 }
2105 }
2106
2107 browserParent->SendRealDragEvent(*aEvent->AsDragEvent(), action,
2108 dropEffect, principal, csp);
2109 return;
2110 }
2111 default: {
2112 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"
, 2112); AnnotateMozCrashReason("MOZ_CRASH(" "Attempt to send non-whitelisted event?"
")"); do { *((volatile int*)__null) = 2112; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2113 }
2114 }
2115}
2116
2117bool EventStateManager::IsRemoteTarget(nsIContent* target) {
2118 return BrowserParent::GetFrom(target) || BrowserBridgeChild::GetFrom(target);
2119}
2120
2121bool EventStateManager::IsTopLevelRemoteTarget(nsIContent* target) {
2122 return !!BrowserParent::GetFrom(target);
2123}
2124
2125bool EventStateManager::HandleCrossProcessEvent(WidgetEvent* aEvent,
2126 nsEventStatus* aStatus) {
2127 if (!aEvent->CanBeSentToRemoteProcess()) {
2128 return false;
2129 }
2130
2131 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"
, 2132); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aEvent->HasBeenPostedToRemoteProcess()"
") (" "Why do we need to post same event to remote processes again?"
")"); do { *((volatile int*)__null) = 2132; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2132 "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"
, 2132); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aEvent->HasBeenPostedToRemoteProcess()"
") (" "Why do we need to post same event to remote processes again?"
")"); do { *((volatile int*)__null) = 2132; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2133
2134 // Collect the remote event targets we're going to forward this
2135 // event to.
2136 //
2137 // NB: the elements of |remoteTargets| must be unique, for correctness.
2138 AutoTArray<RefPtr<BrowserParent>, 1> remoteTargets;
2139 if (aEvent->mClass != eTouchEventClass || aEvent->mMessage == eTouchStart) {
2140 // If this event only has one target, and it's remote, add it to
2141 // the array.
2142 nsIFrame* frame = aEvent->mMessage == eDragExit
2143 ? sLastDragOverFrame.GetFrame()
2144 : GetEventTarget();
2145 nsIContent* target = frame ? frame->GetContent() : nullptr;
2146 if (BrowserParent* remoteTarget = BrowserParent::GetFrom(target)) {
2147 remoteTargets.AppendElement(remoteTarget);
2148 }
2149 } else {
2150 // This is a touch event with possibly multiple touch points.
2151 // Each touch point may have its own target. So iterate through
2152 // all of them and collect the unique set of targets for event
2153 // forwarding.
2154 //
2155 // This loop is similar to the one used in
2156 // PresShell::DispatchTouchEvent().
2157 const WidgetTouchEvent::TouchArray& touches =
2158 aEvent->AsTouchEvent()->mTouches;
2159 for (uint32_t i = 0; i < touches.Length(); ++i) {
2160 Touch* touch = touches[i];
2161 // NB: the |mChanged| check is an optimization, subprocesses can
2162 // compute this for themselves. If the touch hasn't changed, we
2163 // may be able to avoid forwarding the event entirely (which is
2164 // not free).
2165 if (!touch || !touch->mChanged) {
2166 continue;
2167 }
2168 nsCOMPtr<EventTarget> targetPtr = touch->mTarget;
2169 if (!targetPtr) {
2170 continue;
2171 }
2172 nsCOMPtr<nsIContent> target = do_QueryInterface(targetPtr);
2173 BrowserParent* remoteTarget = BrowserParent::GetFrom(target);
2174 if (remoteTarget && !remoteTargets.Contains(remoteTarget)) {
2175 remoteTargets.AppendElement(remoteTarget);
2176 }
2177 }
2178 }
2179
2180 if (remoteTargets.Length() == 0) {
2181 return false;
2182 }
2183
2184 // Dispatch the event to the remote target.
2185 for (uint32_t i = 0; i < remoteTargets.Length(); ++i) {
2186 DispatchCrossProcessEvent(aEvent, remoteTargets[i], aStatus);
2187 }
2188 return aEvent->HasBeenPostedToRemoteProcess();
2189}
2190
2191//
2192// CreateClickHoldTimer
2193//
2194// Fire off a timer for determining if the user wants click-hold. This timer
2195// is a one-shot that will be cancelled when the user moves enough to fire
2196// a drag.
2197//
2198void EventStateManager::CreateClickHoldTimer(nsPresContext* inPresContext,
2199 nsIFrame* inDownFrame,
2200 WidgetGUIEvent* inMouseDownEvent) {
2201 if (!inMouseDownEvent->IsTrusted() ||
2202 IsTopLevelRemoteTarget(mGestureDownContent) ||
2203 PointerLockManager::IsLocked()) {
2204 return;
2205 }
2206
2207 // just to be anal (er, safe)
2208 if (mClickHoldTimer) {
2209 mClickHoldTimer->Cancel();
2210 mClickHoldTimer = nullptr;
2211 }
2212
2213 // if content clicked on has a popup, don't even start the timer
2214 // since we'll end up conflicting and both will show.
2215 if (mGestureDownContent &&
2216 nsContentUtils::HasNonEmptyAttr(mGestureDownContent, kNameSpaceID_None,
2217 nsGkAtoms::popup)) {
2218 return;
2219 }
2220
2221 int32_t clickHoldDelay = StaticPrefs::ui_click_hold_context_menus_delay();
2222 NS_NewTimerWithFuncCallback(
2223 getter_AddRefs(mClickHoldTimer), sClickHoldCallback, this, clickHoldDelay,
2224 nsITimer::TYPE_ONE_SHOT, "EventStateManager::CreateClickHoldTimer");
2225} // CreateClickHoldTimer
2226
2227//
2228// KillClickHoldTimer
2229//
2230// Stop the timer that would show the context menu dead in its tracks
2231//
2232void EventStateManager::KillClickHoldTimer() {
2233 if (mClickHoldTimer) {
2234 mClickHoldTimer->Cancel();
2235 mClickHoldTimer = nullptr;
2236 }
2237}
2238
2239//
2240// sClickHoldCallback
2241//
2242// This fires after the mouse has been down for a certain length of time.
2243//
2244void EventStateManager::sClickHoldCallback(nsITimer* aTimer, void* aESM) {
2245 RefPtr<EventStateManager> self = static_cast<EventStateManager*>(aESM);
2246 if (self) {
2247 self->FireContextClick();
2248 }
2249
2250 // NOTE: |aTimer| and |self->mAutoHideTimer| are invalid after calling
2251 // ClosePopup();
2252
2253} // sAutoHideCallback
2254
2255//
2256// FireContextClick
2257//
2258// If we're this far, our timer has fired, which means the mouse has been down
2259// for a certain period of time and has not moved enough to generate a
2260// dragGesture. We can be certain the user wants a context-click at this stage,
2261// so generate a dom event and fire it in.
2262//
2263// After the event fires, check if PreventDefault() has been set on the event
2264// which means that someone either ate the event or put up a context menu. This
2265// is our cue to stop tracking the drag gesture. If we always did this,
2266// draggable items w/out a context menu wouldn't be draggable after a certain
2267// length of time, which is _not_ what we want.
2268//
2269void EventStateManager::FireContextClick() {
2270 if (!mGestureDownContent || !mPresContext || PointerLockManager::IsLocked()) {
2271 return;
2272 }
2273
2274#ifdef XP_MACOSX
2275 // Hack to ensure that we don't show a context menu when the user
2276 // let go of the mouse after a long cpu-hogging operation prevented
2277 // us from handling any OS events. See bug 117589.
2278 if (!CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState,
2279 kCGMouseButtonLeft))
2280 return;
2281#endif
2282
2283 nsEventStatus status = nsEventStatus_eIgnore;
2284
2285 // Dispatch to the DOM. We have to fake out the ESM and tell it that the
2286 // current target frame is actually where the mouseDown occurred, otherwise it
2287 // will use the frame the mouse is currently over which may or may not be
2288 // the same. (Note: saari and I have decided that we don't have to reset
2289 // |mCurrentTarget| when we're through because no one else is doing anything
2290 // more with this event and it will get reset on the very next event to the
2291 // correct frame).
2292 mCurrentTarget = mPresContext->GetPrimaryFrameFor(mGestureDownContent);
2293 // make sure the widget sticks around
2294 nsCOMPtr<nsIWidget> targetWidget;
2295 if (mCurrentTarget && (targetWidget = mCurrentTarget->GetNearestWidget())) {
2296 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"
, 2298); MOZ_PretendNoReturn(); } } while (0)
2297 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"
, 2298); MOZ_PretendNoReturn(); } } while (0)
2298 "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"
, 2298); MOZ_PretendNoReturn(); } } while (0)
;
2299
2300 // before dispatching, check that we're not on something that
2301 // doesn't get a context menu
2302 bool allowedToDispatch = true;
2303
2304 if (mGestureDownContent->IsAnyOfXULElements(nsGkAtoms::scrollbar,
2305 nsGkAtoms::scrollbarbutton,
2306 nsGkAtoms::button)) {
2307 allowedToDispatch = false;
2308 } else if (mGestureDownContent->IsXULElement(nsGkAtoms::toolbarbutton)) {
2309 // a <toolbarbutton> that has the container attribute set
2310 // will already have its own dropdown.
2311 if (nsContentUtils::HasNonEmptyAttr(
2312 mGestureDownContent, kNameSpaceID_None, nsGkAtoms::container)) {
2313 allowedToDispatch = false;
2314 } else {
2315 // If the toolbar button has an open menu, don't attempt to open
2316 // a second menu
2317 if (mGestureDownContent->IsElement() &&
2318 mGestureDownContent->AsElement()->AttrValueIs(
2319 kNameSpaceID_None, nsGkAtoms::open, nsGkAtoms::_true,
2320 eCaseMatters)) {
2321 allowedToDispatch = false;
2322 }
2323 }
2324 } else if (mGestureDownContent->IsHTMLElement()) {
2325 if (const auto* formCtrl =
2326 nsIFormControl::FromNode(mGestureDownContent)) {
2327 allowedToDispatch =
2328 formCtrl->IsTextControl(/*aExcludePassword*/ false) ||
2329 formCtrl->ControlType() == FormControlType::InputFile;
2330 } else if (mGestureDownContent->IsAnyOfHTMLElements(
2331 nsGkAtoms::embed, nsGkAtoms::object, nsGkAtoms::label)) {
2332 allowedToDispatch = false;
2333 }
2334 }
2335
2336 if (allowedToDispatch) {
2337 // init the event while mCurrentTarget is still good
2338 WidgetPointerEvent event(true, eContextMenu, targetWidget);
2339 event.mClickCount = 1;
2340 FillInEventFromGestureDown(&event);
2341
2342 // we need to forget the clicking content and click count for the
2343 // following eMouseUp event when click-holding context menus
2344 LastMouseDownInfo& mouseDownInfo = GetLastMouseDownInfo(event.mButton);
2345 mouseDownInfo.mLastMouseDownContent = nullptr;
2346 mouseDownInfo.mClickCount = 0;
2347 mouseDownInfo.mLastMouseDownInputControlType = Nothing();
2348
2349 // stop selection tracking, we're in control now
2350 if (mCurrentTarget) {
2351 RefPtr<nsFrameSelection> frameSel = mCurrentTarget->GetFrameSelection();
2352
2353 if (frameSel && frameSel->GetDragState()) {
2354 // note that this can cause selection changed events to fire if we're
2355 // in a text field, which will null out mCurrentTarget
2356 frameSel->SetDragState(false);
2357 }
2358 }
2359
2360 AutoHandlingUserInputStatePusher userInpStatePusher(true, &event);
2361
2362 // dispatch to DOM
2363 RefPtr<nsPresContext> presContext = mPresContext;
2364
2365 // The contextmenu event handled by PresShell will apply to elements (not
2366 // all nodes) correctly and will be dispatched to EventStateManager for
2367 // further handling preventing click event and stopping tracking drag
2368 // gesture.
2369 if (RefPtr<PresShell> presShell = presContext->GetPresShell()) {
2370 presShell->HandleEvent(mCurrentTarget, &event, false, &status);
2371 }
2372
2373 // We don't need to dispatch to frame handling because no frames
2374 // watch eContextMenu except for nsMenuFrame and that's only for
2375 // dismissal. That's just as well since we don't really know
2376 // which frame to send it to.
2377 }
2378 }
2379
2380 // stop tracking a drag whatever the event has been handled or not.
2381 StopTrackingDragGesture(true);
2382
2383 KillClickHoldTimer();
2384
2385} // FireContextClick
2386
2387//
2388// BeginTrackingDragGesture
2389//
2390// Record that the mouse has gone down and that we should move to TRACKING state
2391// of d&d gesture tracker.
2392//
2393// We also use this to track click-hold context menus. When the mouse goes down,
2394// fire off a short timer. If the timer goes off and we have yet to fire the
2395// drag gesture (ie, the mouse hasn't moved a certain distance), then we can
2396// assume the user wants a click-hold, so fire a context-click event. We only
2397// want to cancel the drag gesture if the context-click event is handled.
2398//
2399void EventStateManager::BeginTrackingDragGesture(nsPresContext* aPresContext,
2400 WidgetMouseEvent* inDownEvent,
2401 nsIFrame* inDownFrame) {
2402 if (!inDownEvent->mWidget) {
2403 return;
2404 }
2405
2406 // Note that |inDownEvent| could be either a mouse down event or a
2407 // synthesized mouse move event.
2408 SetGestureDownPoint(inDownEvent);
2409
2410 if (inDownFrame) {
2411 inDownFrame->GetContentForEvent(inDownEvent,
2412 getter_AddRefs(mGestureDownContent));
2413
2414 mGestureDownFrameOwner = inDownFrame->GetContent();
2415 if (!mGestureDownFrameOwner) {
2416 mGestureDownFrameOwner = mGestureDownContent;
2417 }
2418 }
2419 mGestureModifiers = inDownEvent->mModifiers;
2420 mGestureDownButtons = inDownEvent->mButtons;
2421 mGestureDownButton = inDownEvent->mButton;
2422
2423 if (inDownEvent->mMessage != eMouseTouchDrag &&
2424 StaticPrefs::ui_click_hold_context_menus()) {
2425 // fire off a timer to track click-hold
2426 CreateClickHoldTimer(aPresContext, inDownFrame, inDownEvent);
2427 }
2428}
2429
2430void EventStateManager::SetGestureDownPoint(WidgetGUIEvent* aEvent) {
2431 mGestureDownPoint =
2432 GetEventRefPoint(aEvent) + aEvent->mWidget->WidgetToScreenOffset();
2433}
2434
2435LayoutDeviceIntPoint EventStateManager::GetEventRefPoint(
2436 WidgetEvent* aEvent) const {
2437 auto touchEvent = aEvent->AsTouchEvent();
2438 return (touchEvent && !touchEvent->mTouches.IsEmpty())
2439 ? aEvent->AsTouchEvent()->mTouches[0]->mRefPoint
2440 : aEvent->mRefPoint;
2441}
2442
2443void EventStateManager::BeginTrackingRemoteDragGesture(
2444 nsIContent* aContent, RemoteDragStartData* aDragStartData) {
2445 mGestureDownContent = aContent;
2446 mGestureDownFrameOwner = aContent;
2447 mGestureDownInTextControl =
2448 aContent && aContent->IsInNativeAnonymousSubtree() &&
2449 TextControlElement::FromNodeOrNull(
2450 aContent->GetClosestNativeAnonymousSubtreeRootParentOrHost());
2451 mGestureDownDragStartData = aDragStartData;
2452}
2453
2454//
2455// StopTrackingDragGesture
2456//
2457// Record that the mouse has gone back up so that we should leave the TRACKING
2458// state of d&d gesture tracker and return to the START state.
2459//
2460void EventStateManager::StopTrackingDragGesture(bool aClearInChildProcesses) {
2461 mGestureDownContent = nullptr;
2462 mGestureDownFrameOwner = nullptr;
2463 mGestureDownInTextControl = false;
2464 mGestureDownDragStartData = nullptr;
2465
2466 // If a content process starts a drag but the mouse is released before the
2467 // parent starts the actual drag, the content process will think a drag is
2468 // still happening. Inform any child processes with active drags that the drag
2469 // should be stopped.
2470 if (!aClearInChildProcesses || !XRE_IsParentProcess()) {
2471 return;
2472 }
2473
2474 // Only notify if there is NOT a drag session active in the parent.
2475 RefPtr<nsIDragSession> dragSession =
2476 nsContentUtils::GetDragSession(mPresContext);
2477 if (dragSession) {
2478 return;
2479 }
2480 nsCOMPtr<nsIDragService> dragService =
2481 do_GetService("@mozilla.org/widget/dragservice;1");
2482 if (!dragService) {
2483 return;
2484 }
2485 dragService->RemoveAllBrowsers();
2486}
2487
2488void EventStateManager::FillInEventFromGestureDown(WidgetMouseEvent* aEvent) {
2489 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"
, 2490); MOZ_PretendNoReturn(); } } while (0)
2490 "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"
, 2490); MOZ_PretendNoReturn(); } } while (0)
;
2491
2492 // Set the coordinates in the new event to the coordinates of
2493 // the old event, adjusted for the fact that the widget might be
2494 // different
2495 aEvent->mRefPoint =
2496 mGestureDownPoint - aEvent->mWidget->WidgetToScreenOffset();
2497 aEvent->mModifiers = mGestureModifiers;
2498 aEvent->mButtons = mGestureDownButtons;
2499 if (aEvent->mMessage == eContextMenu) {
2500 aEvent->mButton = mGestureDownButton;
2501 }
2502}
2503
2504void EventStateManager::MaybeFirePointerCancel(WidgetInputEvent* aEvent) {
2505 RefPtr<PresShell> presShell = mPresContext->GetPresShell();
2506 AutoWeakFrame targetFrame = mCurrentTarget;
2507
2508 if (!presShell || !targetFrame) {
2509 return;
2510 }
2511
2512 nsCOMPtr<nsIContent> content;
2513 targetFrame->GetContentForEvent(aEvent, getter_AddRefs(content));
2514 if (!content) {
2515 return;
2516 }
2517
2518 nsEventStatus status = nsEventStatus_eIgnore;
2519
2520 if (WidgetMouseEvent* aMouseEvent = aEvent->AsMouseEvent()) {
2521 WidgetPointerEvent event(*aMouseEvent);
2522 PointerEventHandler::InitPointerEventFromMouse(&event, aMouseEvent,
2523 ePointerCancel);
2524
2525 event.convertToPointer = false;
2526 presShell->HandleEventWithTarget(&event, targetFrame, content, &status);
2527 } else if (WidgetTouchEvent* aTouchEvent = aEvent->AsTouchEvent()) {
2528 WidgetPointerEvent event(aTouchEvent->IsTrusted(), ePointerCancel,
2529 aTouchEvent->mWidget);
2530
2531 PointerEventHandler::InitPointerEventFromTouch(event, *aTouchEvent,
2532 *aTouchEvent->mTouches[0]);
2533
2534 event.convertToPointer = false;
2535 presShell->HandleEventWithTarget(&event, targetFrame, content, &status);
2536 } else {
2537 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"
, 2537); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ")")
; do { *((volatile int*)__null) = 2537; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2538 }
2539
2540 // HandleEventWithTarget clears out mCurrentTarget, which may be used in the
2541 // caller GenerateDragGesture. We have to restore mCurrentTarget.
2542 mCurrentTarget = targetFrame;
2543}
2544
2545bool EventStateManager::IsEventOutsideDragThreshold(
2546 WidgetInputEvent* aEvent) const {
2547 static int32_t sPixelThresholdX = 0;
2548 static int32_t sPixelThresholdY = 0;
2549
2550 if (!sPixelThresholdX) {
2551 sPixelThresholdX =
2552 LookAndFeel::GetInt(LookAndFeel::IntID::DragThresholdX, 0);
2553 sPixelThresholdY =
2554 LookAndFeel::GetInt(LookAndFeel::IntID::DragThresholdY, 0);
2555 if (sPixelThresholdX <= 0) {
2556 sPixelThresholdX = 5;
2557 }
2558 if (sPixelThresholdY <= 0) {
2559 sPixelThresholdY = 5;
2560 }
2561 }
2562
2563 LayoutDeviceIntPoint pt =
2564 aEvent->mWidget->WidgetToScreenOffset() + GetEventRefPoint(aEvent);
2565 LayoutDeviceIntPoint distance = pt - mGestureDownPoint;
2566 return Abs(distance.x) > sPixelThresholdX ||
2567 Abs(distance.y) > sPixelThresholdY;
2568}
2569
2570//
2571// GenerateDragGesture
2572//
2573// If we're in the TRACKING state of the d&d gesture tracker, check the current
2574// position of the mouse in relation to the old one. If we've moved a sufficient
2575// amount from the mouse down, then fire off a drag gesture event.
2576void EventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
2577 WidgetInputEvent* aEvent) {
2578 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"
, 2578); MOZ_PretendNoReturn(); } } while (0)
;
2579 if (!IsTrackingDragGesture()) {
2580 return;
2581 }
2582
2583 AutoWeakFrame targetFrameBefore = mCurrentTarget;
2584 auto autoRestore = MakeScopeExit([&] { mCurrentTarget = targetFrameBefore; });
2585 mCurrentTarget = mGestureDownFrameOwner->GetPrimaryFrame();
2586
2587 if (!mCurrentTarget || !mCurrentTarget->GetNearestWidget()) {
2588 StopTrackingDragGesture(true);
2589 return;
2590 }
2591
2592 // Check if selection is tracking drag gestures, if so
2593 // don't interfere!
2594 if (mCurrentTarget) {
2595 RefPtr<nsFrameSelection> frameSel = mCurrentTarget->GetFrameSelection();
2596 if (frameSel && frameSel->GetDragState()) {
2597 StopTrackingDragGesture(true);
2598 return;
2599 }
2600 }
2601
2602 // If non-native code is capturing the mouse don't start a drag.
2603 if (PresShell::IsMouseCapturePreventingDrag()) {
2604 StopTrackingDragGesture(true);
2605 return;
2606 }
2607
2608 if (!IsEventOutsideDragThreshold(aEvent)) {
2609 // To keep the old behavior, flush layout even if we don't start dnd.
2610 FlushLayout(aPresContext);
2611 return;
2612 }
2613
2614 if (StaticPrefs::ui_click_hold_context_menus()) {
2615 // stop the click-hold before we fire off the drag gesture, in case
2616 // it takes a long time
2617 KillClickHoldTimer();
2618 }
2619
2620 nsCOMPtr<nsIDocShell> docshell = aPresContext->GetDocShell();
2621 if (!docshell) {
2622 return;
2623 }
2624
2625 nsCOMPtr<nsPIDOMWindowOuter> window = docshell->GetWindow();
2626 if (!window) return;
2627
2628 RefPtr<DataTransfer> dataTransfer =
2629 new DataTransfer(window, eDragStart, /* aIsExternal */ false,
2630 /* aClipboardType */ Nothing());
2631 auto protectDataTransfer = MakeScopeExit([&] {
2632 if (dataTransfer) {
2633 dataTransfer->Disconnect();
2634 }
2635 });
2636
2637 RefPtr<Selection> selection;
2638 RefPtr<RemoteDragStartData> remoteDragStartData;
2639 nsCOMPtr<nsIContent> eventContent, targetContent;
2640 nsCOMPtr<nsIPrincipal> principal;
2641 nsCOMPtr<nsIContentSecurityPolicy> csp;
2642 nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
2643 bool allowEmptyDataTransfer = false;
2644 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(eventContent));
2645 if (eventContent) {
2646 // If the content is a text node in a password field, we shouldn't
2647 // allow to drag its raw text. Note that we've supported drag from
2648 // password fields but dragging data was masked text. So, it doesn't
2649 // make sense anyway.
2650 if (eventContent->IsText() && eventContent->HasFlag(NS_MAYBE_MASKED)) {
2651 // However, it makes sense to allow to drag selected password text
2652 // when copying selected password is allowed because users may want
2653 // to use drag and drop rather than copy and paste when web apps
2654 // request to input password twice for conforming new password but
2655 // they used password generator.
2656 TextEditor* textEditor =
2657 nsContentUtils::GetTextEditorFromAnonymousNodeWithoutCreation(
2658 eventContent);
2659 if (!textEditor || !textEditor->IsCopyToClipboardAllowed()) {
2660 StopTrackingDragGesture(true);
2661 return;
2662 }
2663 }
2664 DetermineDragTargetAndDefaultData(
2665 window, eventContent, dataTransfer, &allowEmptyDataTransfer,
2666 getter_AddRefs(selection), getter_AddRefs(remoteDragStartData),
2667 getter_AddRefs(targetContent), getter_AddRefs(principal),
2668 getter_AddRefs(csp), getter_AddRefs(cookieJarSettings));
2669 }
2670
2671 // Stop tracking the drag gesture now. This should stop us from
2672 // reentering GenerateDragGesture inside DOM event processing.
2673 // Pass false to avoid clearing the child process state since a real
2674 // drag should be starting.
2675 StopTrackingDragGesture(false);
2676
2677 if (!targetContent) return;
2678
2679 // Use our targetContent, now that we've determined it, as the
2680 // parent object of the DataTransfer.
2681 nsCOMPtr<nsIContent> parentContent =
2682 targetContent->FindFirstNonChromeOnlyAccessContent();
2683 dataTransfer->SetParentObject(parentContent);
2684
2685 sLastDragOverFrame = nullptr;
2686 nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget();
2687
2688 // get the widget from the target frame
2689 WidgetDragEvent startEvent(aEvent->IsTrusted(), eDragStart, widget);
2690 startEvent.mFlags.mIsSynthesizedForTests =
2691 aEvent->mFlags.mIsSynthesizedForTests;
2692 FillInEventFromGestureDown(&startEvent);
2693
2694 startEvent.mDataTransfer = dataTransfer;
2695 if (aEvent->AsMouseEvent()) {
2696 startEvent.mInputSource = aEvent->AsMouseEvent()->mInputSource;
2697 } else if (aEvent->AsTouchEvent()) {
2698 startEvent.mInputSource = MouseEvent_Binding::MOZ_SOURCE_TOUCH;
2699 } else {
2700 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"
, 2700); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ")")
; do { *((volatile int*)__null) = 2700; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2701 }
2702
2703 // Dispatch to the DOM. By setting mCurrentTarget we are faking
2704 // out the ESM and telling it that the current target frame is
2705 // actually where the mouseDown occurred, otherwise it will use
2706 // the frame the mouse is currently over which may or may not be
2707 // the same.
2708
2709 // Hold onto old target content through the event and reset after.
2710 nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
2711
2712 // Set the current target to the content for the mouse down
2713 mCurrentTargetContent = targetContent;
2714
2715 // Dispatch the dragstart event to the DOM.
2716 nsEventStatus status = nsEventStatus_eIgnore;
2717 EventDispatcher::Dispatch(targetContent, aPresContext, &startEvent, nullptr,
2718 &status);
2719
2720 WidgetDragEvent* event = &startEvent;
2721
2722 nsCOMPtr<nsIObserverService> observerService =
2723 mozilla::services::GetObserverService();
2724 // Emit observer event to allow addons to modify the DataTransfer
2725 // object.
2726 if (observerService) {
2727 observerService->NotifyObservers(dataTransfer, "on-datatransfer-available",
2728 nullptr);
2729 }
2730
2731 if (status != nsEventStatus_eConsumeNoDefault) {
2732 bool dragStarted = DoDefaultDragStart(aPresContext, event, dataTransfer,
2733 allowEmptyDataTransfer, targetContent,
2734 selection, remoteDragStartData,
2735 principal, csp, cookieJarSettings);
2736 if (dragStarted) {
2737 sActiveESM = nullptr;
2738 MaybeFirePointerCancel(aEvent);
2739 aEvent->StopPropagation();
2740 }
2741 }
2742
2743 // Reset mCurretTargetContent to what it was
2744 mCurrentTargetContent = targetBeforeEvent;
2745
2746 // Now flush all pending notifications, for better responsiveness
2747 // while dragging.
2748 FlushLayout(aPresContext);
2749} // GenerateDragGesture
2750
2751void EventStateManager::DetermineDragTargetAndDefaultData(
2752 nsPIDOMWindowOuter* aWindow, nsIContent* aSelectionTarget,
2753 DataTransfer* aDataTransfer, bool* aAllowEmptyDataTransfer,
2754 Selection** aSelection, RemoteDragStartData** aRemoteDragStartData,
2755 nsIContent** aTargetNode, nsIPrincipal** aPrincipal,
2756 nsIContentSecurityPolicy** aCsp,
2757 nsICookieJarSettings** aCookieJarSettings) {
2758 *aTargetNode = nullptr;
2759 *aAllowEmptyDataTransfer = false;
2760 nsCOMPtr<nsIContent> dragDataNode;
2761
2762 nsIContent* editingElement = aSelectionTarget->IsEditable()
2763 ? aSelectionTarget->GetEditingHost()
2764 : nullptr;
2765
2766 // In chrome, only allow dragging inside editable areas.
2767 bool isChromeContext = !aWindow->GetBrowsingContext()->IsContent();
2768 if (isChromeContext && !editingElement) {
2769 if (mGestureDownDragStartData) {
2770 // A child process started a drag so use any data it assigned for the dnd
2771 // session.
2772 mGestureDownDragStartData->AddInitialDnDDataTo(aDataTransfer, aPrincipal,
2773 aCsp, aCookieJarSettings);
2774 mGestureDownDragStartData.forget(aRemoteDragStartData);
2775 *aAllowEmptyDataTransfer = true;
2776 }
2777 } else {
2778 mGestureDownDragStartData = nullptr;
2779
2780 // GetDragData determines if a selection, link or image in the content
2781 // should be dragged, and places the data associated with the drag in the
2782 // data transfer.
2783 // mGestureDownContent is the node where the mousedown event for the drag
2784 // occurred, and aSelectionTarget is the node to use when a selection is
2785 // used
2786 bool canDrag;
2787 bool wasAlt = (mGestureModifiers & MODIFIER_ALT) != 0;
2788 nsresult rv = nsContentAreaDragDrop::GetDragData(
2789 aWindow, mGestureDownContent, aSelectionTarget, wasAlt, aDataTransfer,
2790 &canDrag, aSelection, getter_AddRefs(dragDataNode), aCsp,
2791 aCookieJarSettings);
2792 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !canDrag) {
2793 return;
2794 }
2795 }
2796
2797 // if GetDragData returned a node, use that as the node being dragged.
2798 // Otherwise, if a selection is being dragged, use the node within the
2799 // selection that was dragged. Otherwise, just use the mousedown target.
2800 nsIContent* dragContent = mGestureDownContent;
2801 if (dragDataNode)
2802 dragContent = dragDataNode;
2803 else if (*aSelection)
2804 dragContent = aSelectionTarget;
2805
2806 nsIContent* originalDragContent = dragContent;
2807
2808 // If a selection isn't being dragged, look for an ancestor with the
2809 // draggable property set. If one is found, use that as the target of the
2810 // drag instead of the node that was clicked on. If a draggable node wasn't
2811 // found, just use the clicked node.
2812 if (!*aSelection) {
2813 while (dragContent) {
2814 if (auto htmlElement = nsGenericHTMLElement::FromNode(dragContent)) {
2815 if (htmlElement->Draggable()) {
2816 // We let draggable elements to trigger dnd even if there is no data
2817 // in the DataTransfer.
2818 *aAllowEmptyDataTransfer = true;
2819 break;
2820 }
2821 } else {
2822 if (dragContent->IsXULElement()) {
2823 // All XUL elements are draggable, so if a XUL element is
2824 // encountered, stop looking for draggable nodes and just use the
2825 // original clicked node instead.
2826 // XXXndeakin
2827 // In the future, we will want to improve this so that XUL has a
2828 // better way to specify whether something is draggable than just
2829 // on/off.
2830 dragContent = mGestureDownContent;
2831 break;
2832 }
2833 // otherwise, it's not an HTML or XUL element, so just keep looking
2834 }
2835 dragContent = dragContent->GetFlattenedTreeParent();
2836 }
2837 }
2838
2839 // if no node in the hierarchy was found to drag, but the GetDragData method
2840 // returned a node, use that returned node. Otherwise, nothing is draggable.
2841 if (!dragContent && dragDataNode) dragContent = dragDataNode;
2842
2843 if (dragContent) {
2844 // if an ancestor node was used instead, clear the drag data
2845 // XXXndeakin rework this a bit. Find a way to just not call GetDragData if
2846 // we don't need to.
2847 if (dragContent != originalDragContent) aDataTransfer->ClearAll();
2848 *aTargetNode = dragContent;
2849 NS_ADDREF(*aTargetNode)(*aTargetNode)->AddRef();
2850 }
2851}
2852
2853bool EventStateManager::DoDefaultDragStart(
2854 nsPresContext* aPresContext, WidgetDragEvent* aDragEvent,
2855 DataTransfer* aDataTransfer, bool aAllowEmptyDataTransfer,
2856 nsIContent* aDragTarget, Selection* aSelection,
2857 RemoteDragStartData* aDragStartData, nsIPrincipal* aPrincipal,
2858 nsIContentSecurityPolicy* aCsp, nsICookieJarSettings* aCookieJarSettings) {
2859 nsCOMPtr<nsIDragService> dragService =
2860 do_GetService("@mozilla.org/widget/dragservice;1");
2861 if (!dragService) return false;
2862
2863 // Default handling for the dragstart event.
2864 //
2865 // First, check if a drag session already exists. This means that the drag
2866 // service was called directly within a draggesture handler. In this case,
2867 // don't do anything more, as it is assumed that the handler is managing
2868 // drag and drop manually. Make sure to return true to indicate that a drag
2869 // began. However, if we're handling drag session for synthesized events,
2870 // we need to initialize some information of the session. Therefore, we
2871 // need to keep going for synthesized case.
2872 if (MOZ_UNLIKELY(!mPresContext)(__builtin_expect(!!(!mPresContext), 0))) {
2873 return true;
2874 }
2875 nsCOMPtr<nsIDragSession> dragSession =
2876 dragService->GetCurrentSession(mPresContext->GetRootWidget());
2877 if (dragSession && !dragSession->IsSynthesizedForTests()) {
2878 return true;
2879 }
2880
2881 // No drag session is currently active, so check if a handler added
2882 // any items to be dragged. If not, there isn't anything to drag.
2883 uint32_t count = 0;
2884 if (aDataTransfer) {
2885 count = aDataTransfer->MozItemCount();
2886 }
2887 if (!aAllowEmptyDataTransfer && !count) {
2888 return false;
2889 }
2890
2891 // Get the target being dragged, which may not be the same as the
2892 // target of the mouse event. If one wasn't set in the
2893 // aDataTransfer during the event handler, just use the original
2894 // target instead.
2895 nsCOMPtr<nsIContent> dragTarget = aDataTransfer->GetDragTarget();
2896 if (!dragTarget) {
2897 dragTarget = aDragTarget;
2898 if (!dragTarget) {
2899 return false;
2900 }
2901 }
2902
2903 // check which drag effect should initially be used. If the effect was not
2904 // set, just use all actions, otherwise Windows won't allow a drop.
2905 uint32_t action = aDataTransfer->EffectAllowedInt();
2906 if (action == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED) {
2907 action = nsIDragService::DRAGDROP_ACTION_COPY |
2908 nsIDragService::DRAGDROP_ACTION_MOVE |
2909 nsIDragService::DRAGDROP_ACTION_LINK;
2910 }
2911
2912 // get any custom drag image that was set
2913 int32_t imageX, imageY;
2914 RefPtr<Element> dragImage = aDataTransfer->GetDragImage(&imageX, &imageY);
2915
2916 nsCOMPtr<nsIArray> transArray = aDataTransfer->GetTransferables(dragTarget);
2917 if (!transArray) {
2918 return false;
2919 }
2920
2921 RefPtr<DataTransfer> dataTransfer;
2922 if (!dragSession) {
2923 // After this function returns, the DataTransfer will be cleared so it
2924 // appears empty to content. We need to pass a DataTransfer into the Drag
2925 // Session, so we need to make a copy.
2926 aDataTransfer->Clone(aDragTarget, eDrop, aDataTransfer->MozUserCancelled(),
2927 false, getter_AddRefs(dataTransfer));
2928
2929 // Copy over the drop effect, as Clone doesn't copy it for us.
2930 dataTransfer->SetDropEffectInt(aDataTransfer->DropEffectInt());
2931 } else {
2932 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"
, 2932); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dragSession->IsSynthesizedForTests()"
")"); do { *((volatile int*)__null) = 2932; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2933 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"
, 2933); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDragEvent->mFlags.mIsSynthesizedForTests"
")"); do { *((volatile int*)__null) = 2933; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2934 // If we're initializing synthesized drag session, we should use given
2935 // DataTransfer as is because it'll be used with following drag events
2936 // in any tests, therefore it should be set to nsIDragSession.dataTransfer
2937 // because it and DragEvent.dataTransfer should be same instance.
2938 dataTransfer = aDataTransfer;
2939 }
2940
2941 // XXXndeakin don't really want to create a new drag DOM event
2942 // here, but we need something to pass to the InvokeDragSession
2943 // methods.
2944 RefPtr<DragEvent> event =
2945 NS_NewDOMDragEvent(dragTarget, aPresContext, aDragEvent);
2946
2947 // Use InvokeDragSessionWithSelection if a selection is being dragged,
2948 // such that the image can be generated from the selected text. However,
2949 // use InvokeDragSessionWithImage if a custom image was set or something
2950 // other than a selection is being dragged.
2951 if (!dragImage && aSelection) {
2952 dragService->InvokeDragSessionWithSelection(
2953 aSelection, aPrincipal, aCsp, aCookieJarSettings, transArray, action,
2954 event, dataTransfer, dragTarget);
2955 } else if (aDragStartData) {
2956 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"
, 2956); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 2956; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2957 dragService->InvokeDragSessionWithRemoteImage(
2958 dragTarget, aPrincipal, aCsp, aCookieJarSettings, transArray, action,
2959 aDragStartData, event, dataTransfer);
2960 } else {
2961 dragService->InvokeDragSessionWithImage(
2962 dragTarget, aPrincipal, aCsp, aCookieJarSettings, transArray, action,
2963 dragImage, imageX, imageY, event, dataTransfer);
2964 }
2965
2966 return true;
2967}
2968
2969void EventStateManager::ChangeZoom(bool aIncrease) {
2970 // Send the zoom change to the top level browser so it will be handled by the
2971 // front end in the same way as other zoom actions.
2972 nsIDocShell* docShell = mDocument->GetDocShell();
2973 if (!docShell) {
2974 return;
2975 }
2976
2977 BrowsingContext* bc = docShell->GetBrowsingContext();
2978 if (!bc) {
2979 return;
2980 }
2981
2982 if (XRE_IsParentProcess()) {
2983 bc->Canonical()->DispatchWheelZoomChange(aIncrease);
2984 } else if (BrowserChild* child = BrowserChild::GetFrom(docShell)) {
2985 child->SendWheelZoomChange(aIncrease);
2986 }
2987}
2988
2989void EventStateManager::DoScrollHistory(int32_t direction) {
2990 nsCOMPtr<nsISupports> pcContainer(mPresContext->GetContainerWeak());
2991 if (pcContainer) {
2992 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(pcContainer));
2993 if (webNav) {
2994 // positive direction to go back one step, nonpositive to go forward
2995 // This is doing user-initiated history traversal, hence we want
2996 // to require that history entries we navigate to have user interaction.
2997 if (direction > 0)
2998 webNav->GoBack(StaticPrefs::browser_navigation_requireUserInteraction(),
2999 true);
3000 else
3001 webNav->GoForward(
3002 StaticPrefs::browser_navigation_requireUserInteraction(), true);
3003 }
3004 }
3005}
3006
3007void EventStateManager::DoScrollZoom(nsIFrame* aTargetFrame,
3008 int32_t adjustment) {
3009 // Exclude content in chrome docshells.
3010 nsIContent* content = aTargetFrame->GetContent();
3011 if (content && !nsContentUtils::IsInChromeDocshell(content->OwnerDoc())) {
3012 // Positive adjustment to decrease zoom, negative to increase
3013 const bool increase = adjustment <= 0;
3014 EnsureDocument(mPresContext);
3015 ChangeZoom(increase);
3016 }
3017}
3018
3019static nsIFrame* GetParentFrameToScroll(nsIFrame* aFrame) {
3020 if (!aFrame) return nullptr;
3021
3022 if (aFrame->StyleDisplay()->mPosition == StylePositionProperty::Fixed &&
3023 nsLayoutUtils::IsReallyFixedPos(aFrame)) {
3024 return aFrame->PresShell()->GetRootScrollContainerFrame();
3025 }
3026 return aFrame->GetParent();
3027}
3028
3029void EventStateManager::DispatchLegacyMouseScrollEvents(
3030 nsIFrame* aTargetFrame, WidgetWheelEvent* aEvent, nsEventStatus* aStatus) {
3031 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"
, 3031); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 3031; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3032 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"
, 3032); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 3032; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3033
3034 if (!aTargetFrame || *aStatus == nsEventStatus_eConsumeNoDefault) {
3035 return;
3036 }
3037
3038 // Ignore mouse wheel transaction for computing legacy mouse wheel
3039 // events' delta value.
3040 // DOM event's delta vales are computed from CSS pixels.
3041 auto scrollAmountInCSSPixels =
3042 CSSIntSize::FromAppUnitsRounded(aEvent->mScrollAmount);
3043
3044 // XXX We don't deal with fractional amount in legacy event, though the
3045 // default action handler (DoScrollText()) deals with it.
3046 // If we implemented such strict computation, we would need additional
3047 // accumulated delta values. It would made the code more complicated.
3048 // And also it would computes different delta values from older version.
3049 // It doesn't make sense to implement such code for legacy events and
3050 // rare cases.
3051 int32_t scrollDeltaX, scrollDeltaY, pixelDeltaX, pixelDeltaY;
3052 switch (aEvent->mDeltaMode) {
3053 case WheelEvent_Binding::DOM_DELTA_PAGE:
3054 scrollDeltaX = !aEvent->mLineOrPageDeltaX
3055 ? 0
3056 : (aEvent->mLineOrPageDeltaX > 0
3057 ? UIEvent_Binding::SCROLL_PAGE_DOWN
3058 : UIEvent_Binding::SCROLL_PAGE_UP);
3059 scrollDeltaY = !aEvent->mLineOrPageDeltaY
3060 ? 0
3061 : (aEvent->mLineOrPageDeltaY > 0
3062 ? UIEvent_Binding::SCROLL_PAGE_DOWN
3063 : UIEvent_Binding::SCROLL_PAGE_UP);
3064 pixelDeltaX = RoundDown(aEvent->mDeltaX * scrollAmountInCSSPixels.width);
3065 pixelDeltaY = RoundDown(aEvent->mDeltaY * scrollAmountInCSSPixels.height);
3066 break;
3067
3068 case WheelEvent_Binding::DOM_DELTA_LINE:
3069 scrollDeltaX = aEvent->mLineOrPageDeltaX;
3070 scrollDeltaY = aEvent->mLineOrPageDeltaY;
3071 pixelDeltaX = RoundDown(aEvent->mDeltaX * scrollAmountInCSSPixels.width);
3072 pixelDeltaY = RoundDown(aEvent->mDeltaY * scrollAmountInCSSPixels.height);
3073 break;
3074
3075 case WheelEvent_Binding::DOM_DELTA_PIXEL:
3076 scrollDeltaX = aEvent->mLineOrPageDeltaX;
3077 scrollDeltaY = aEvent->mLineOrPageDeltaY;
3078 pixelDeltaX = RoundDown(aEvent->mDeltaX);
3079 pixelDeltaY = RoundDown(aEvent->mDeltaY);
3080 break;
3081
3082 default:
3083 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"
, 3083); AnnotateMozCrashReason("MOZ_CRASH(" "Invalid deltaMode value comes"
")"); do { *((volatile int*)__null) = 3083; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
3084 }
3085
3086 // Send the legacy events in following order:
3087 // 1. Vertical scroll
3088 // 2. Vertical pixel scroll (even if #1 isn't consumed)
3089 // 3. Horizontal scroll (even if #1 and/or #2 are consumed)
3090 // 4. Horizontal pixel scroll (even if #3 isn't consumed)
3091
3092 AutoWeakFrame targetFrame(aTargetFrame);
3093
3094 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"
, 3097); 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) = 3097; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3095 !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"
, 3097); 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) = 3097; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3096 "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"
, 3097); 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) = 3097; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3097 "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"
, 3097); 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) = 3097; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
3098 EventState stateX, stateY;
3099 if (scrollDeltaY) {
3100 SendLineScrollEvent(aTargetFrame, aEvent, stateY, scrollDeltaY,
3101 DELTA_DIRECTION_Y);
3102 if (!targetFrame.IsAlive()) {
3103 *aStatus = nsEventStatus_eConsumeNoDefault;
3104 return;
3105 }
3106 }
3107
3108 if (pixelDeltaY) {
3109 SendPixelScrollEvent(aTargetFrame, aEvent, stateY, pixelDeltaY,
3110 DELTA_DIRECTION_Y);
3111 if (!targetFrame.IsAlive()) {
3112 *aStatus = nsEventStatus_eConsumeNoDefault;
3113 return;
3114 }
3115 }
3116
3117 if (scrollDeltaX) {
3118 SendLineScrollEvent(aTargetFrame, aEvent, stateX, scrollDeltaX,
3119 DELTA_DIRECTION_X);
3120 if (!targetFrame.IsAlive()) {
3121 *aStatus = nsEventStatus_eConsumeNoDefault;
3122 return;
3123 }
3124 }
3125
3126 if (pixelDeltaX) {
3127 SendPixelScrollEvent(aTargetFrame, aEvent, stateX, pixelDeltaX,
3128 DELTA_DIRECTION_X);
3129 if (!targetFrame.IsAlive()) {
3130 *aStatus = nsEventStatus_eConsumeNoDefault;
3131 return;
3132 }
3133 }
3134
3135 if (stateY.mDefaultPrevented) {
3136 *aStatus = nsEventStatus_eConsumeNoDefault;
3137 aEvent->PreventDefault(!stateY.mDefaultPreventedByContent);
3138 }
3139
3140 if (stateX.mDefaultPrevented) {
3141 *aStatus = nsEventStatus_eConsumeNoDefault;
3142 aEvent->PreventDefault(!stateX.mDefaultPreventedByContent);
3143 }
3144}
3145
3146void EventStateManager::SendLineScrollEvent(nsIFrame* aTargetFrame,
3147 WidgetWheelEvent* aEvent,
3148 EventState& aState, int32_t aDelta,
3149 DeltaDirection aDeltaDirection) {
3150 nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
3151 if (!targetContent) {
3152 targetContent = GetFocusedElement();
3153 if (!targetContent) {
3154 return;
3155 }
3156 }
3157
3158 while (targetContent->IsText()) {
3159 targetContent = targetContent->GetFlattenedTreeParent();
3160 }
3161
3162 WidgetMouseScrollEvent event(aEvent->IsTrusted(),
3163 eLegacyMouseLineOrPageScroll, aEvent->mWidget);
3164 event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
3165 event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
3166 event.mRefPoint = aEvent->mRefPoint;
3167 event.mTimeStamp = aEvent->mTimeStamp;
3168 event.mModifiers = aEvent->mModifiers;
3169 event.mButtons = aEvent->mButtons;
3170 event.mIsHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
3171 event.mDelta = aDelta;
3172 event.mInputSource = aEvent->mInputSource;
3173
3174 RefPtr<nsPresContext> presContext = aTargetFrame->PresContext();
3175 nsEventStatus status = nsEventStatus_eIgnore;
3176 EventDispatcher::Dispatch(targetContent, presContext, &event, nullptr,
3177 &status);
3178 aState.mDefaultPrevented =
3179 event.DefaultPrevented() || status == nsEventStatus_eConsumeNoDefault;
3180 aState.mDefaultPreventedByContent = event.DefaultPreventedByContent();
3181}
3182
3183void EventStateManager::SendPixelScrollEvent(nsIFrame* aTargetFrame,
3184 WidgetWheelEvent* aEvent,
3185 EventState& aState,
3186 int32_t aPixelDelta,
3187 DeltaDirection aDeltaDirection) {
3188 nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
3189 if (!targetContent) {
3190 targetContent = GetFocusedElement();
3191 if (!targetContent) {
3192 return;
3193 }
3194 }
3195
3196 while (targetContent->IsText()) {
3197 targetContent = targetContent->GetFlattenedTreeParent();
3198 }
3199
3200 WidgetMouseScrollEvent event(aEvent->IsTrusted(), eLegacyMousePixelScroll,
3201 aEvent->mWidget);
3202 event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
3203 event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
3204 event.mRefPoint = aEvent->mRefPoint;
3205 event.mTimeStamp = aEvent->mTimeStamp;
3206 event.mModifiers = aEvent->mModifiers;
3207 event.mButtons = aEvent->mButtons;
3208 event.mIsHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
3209 event.mDelta = aPixelDelta;
3210 event.mInputSource = aEvent->mInputSource;
3211
3212 RefPtr<nsPresContext> presContext = aTargetFrame->PresContext();
3213 nsEventStatus status = nsEventStatus_eIgnore;
3214 EventDispatcher::Dispatch(targetContent, presContext, &event, nullptr,
3215 &status);
3216 aState.mDefaultPrevented =
3217 event.DefaultPrevented() || status == nsEventStatus_eConsumeNoDefault;
3218 aState.mDefaultPreventedByContent = event.DefaultPreventedByContent();
3219}
3220
3221ScrollContainerFrame*
3222EventStateManager::ComputeScrollTargetAndMayAdjustWheelEvent(
3223 nsIFrame* aTargetFrame, WidgetWheelEvent* aEvent,
3224 ComputeScrollTargetOptions aOptions) {
3225 return ComputeScrollTargetAndMayAdjustWheelEvent(
3226 aTargetFrame, aEvent->mDeltaX, aEvent->mDeltaY, aEvent, aOptions);
3227}
3228
3229// Overload ComputeScrollTargetAndMayAdjustWheelEvent method to allow passing
3230// "test" dx and dy when looking for which scrollbarmediators to activate when
3231// two finger down on trackpad and before any actual motion
3232ScrollContainerFrame*
3233EventStateManager::ComputeScrollTargetAndMayAdjustWheelEvent(
3234 nsIFrame* aTargetFrame, double aDirectionX, double aDirectionY,
3235 WidgetWheelEvent* aEvent, ComputeScrollTargetOptions aOptions) {
3236 bool isAutoDir = false;
3237 bool honoursRoot = false;
3238 if (MAY_BE_ADJUSTED_BY_AUTO_DIR & aOptions) {
3239 // If the scroll is respected as auto-dir, aDirection* should always be
3240 // equivalent to the event's delta vlaues(Currently, there are only one case
3241 // where aDirection*s have different values from the widget wheel event's
3242 // original delta values and the only case isn't auto-dir, see
3243 // ScrollbarsForWheel::TemporarilyActivateAllPossibleScrollTargets).
3244 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"
, 3245); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDirectionX == aEvent->mDeltaX && aDirectionY == aEvent->mDeltaY"
")"); do { *((volatile int*)__null) = 3245; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3245 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"
, 3245); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDirectionX == aEvent->mDeltaX && aDirectionY == aEvent->mDeltaY"
")"); do { *((volatile int*)__null) = 3245; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3246
3247 WheelDeltaAdjustmentStrategy strategy =
3248 GetWheelDeltaAdjustmentStrategy(*aEvent);
3249 switch (strategy) {
3250 case WheelDeltaAdjustmentStrategy::eAutoDir:
3251 isAutoDir = true;
3252 honoursRoot = false;
3253 break;
3254 case WheelDeltaAdjustmentStrategy::eAutoDirWithRootHonour:
3255 isAutoDir = true;
3256 honoursRoot = true;
3257 break;
3258 default:
3259 break;
3260 }
3261 }
3262
3263 if (aOptions & PREFER_MOUSE_WHEEL_TRANSACTION) {
3264 // If the user recently scrolled with the mousewheel, then they probably
3265 // want to scroll the same view as before instead of the view under the
3266 // cursor. WheelTransaction tracks the frame currently being
3267 // scrolled with the mousewheel. We consider the transaction ended when the
3268 // mouse moves more than "mousewheel.transaction.ignoremovedelay"
3269 // milliseconds after the last scroll operation, or any time the mouse moves
3270 // out of the frame, or when more than "mousewheel.transaction.timeout"
3271 // milliseconds have passed after the last operation, even if the mouse
3272 // hasn't moved.
3273 nsIFrame* lastScrollFrame = WheelTransaction::GetScrollTargetFrame();
3274 if (lastScrollFrame) {
3275 ScrollContainerFrame* scrollContainerFrame =
3276 lastScrollFrame->GetScrollTargetFrame();
3277 if (scrollContainerFrame) {
3278 if (isAutoDir) {
3279 ESMAutoDirWheelDeltaAdjuster adjuster(*aEvent, *lastScrollFrame,
3280 honoursRoot);
3281 // Note that calling this function will not always cause the delta to
3282 // be adjusted, it only adjusts the delta when it should, because
3283 // Adjust() internally calls ShouldBeAdjusted() before making
3284 // adjustment.
3285 adjuster.Adjust();
3286 }
3287 return scrollContainerFrame;
3288 }
3289 }
3290 }
3291
3292 // If the event doesn't cause scroll actually, we cannot find scroll target
3293 // because we check if the event can cause scroll actually on each found
3294 // scrollable frame.
3295 if (!aDirectionX && !aDirectionY) {
3296 return nullptr;
3297 }
3298
3299 bool checkIfScrollableX;
3300 bool checkIfScrollableY;
3301 if (isAutoDir) {
3302 // Always check the frame's scrollability in both the two directions for an
3303 // auto-dir scroll. That is, for an auto-dir scroll,
3304 // PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS and
3305 // PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS should be ignored.
3306 checkIfScrollableX = true;
3307 checkIfScrollableY = true;
3308 } else {
3309 checkIfScrollableX =
3310 aDirectionX &&
3311 (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS);
3312 checkIfScrollableY =
3313 aDirectionY &&
3314 (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS);
3315 }
3316
3317 nsIFrame* scrollFrame = !(aOptions & START_FROM_PARENT)
3318 ? aTargetFrame
3319 : GetParentFrameToScroll(aTargetFrame);
3320 for (; scrollFrame; scrollFrame = GetParentFrameToScroll(scrollFrame)) {
3321 // Check whether the frame wants to provide us with a scrollable view.
3322 ScrollContainerFrame* scrollContainerFrame =
3323 scrollFrame->GetScrollTargetFrame();
3324 if (!scrollContainerFrame) {
3325 nsMenuPopupFrame* menuPopupFrame = do_QueryFrame(scrollFrame);
3326 if (menuPopupFrame) {
3327 return nullptr;
3328 }
3329 continue;
3330 }
3331
3332 if (!checkIfScrollableX && !checkIfScrollableY) {
3333 return scrollContainerFrame;
3334 }
3335
3336 // If the frame disregards the direction the user is trying to scroll, then
3337 // it should just bubbles the scroll event up to its parental scroll frame
3338
3339 Maybe<layers::ScrollDirection> disregardedDirection =
3340 WheelHandlingUtils::GetDisregardedWheelScrollDirection(scrollFrame);
3341 if (disregardedDirection) {
3342 switch (disregardedDirection.ref()) {
3343 case layers::ScrollDirection::eHorizontal:
3344 if (checkIfScrollableX) {
3345 continue;
3346 }
3347 break;
3348 case layers::ScrollDirection::eVertical:
3349 if (checkIfScrollableY) {
3350 continue;
3351 }
3352 break;
3353 }
3354 }
3355
3356 layers::ScrollDirections directions =
3357 scrollContainerFrame
3358 ->GetAvailableScrollingDirectionsForUserInputEvents();
3359 if ((!(directions.contains(layers::ScrollDirection::eVertical)) &&
3360 !(directions.contains(layers::ScrollDirection::eHorizontal))) ||
3361 (checkIfScrollableY && !checkIfScrollableX &&
3362 !(directions.contains(layers::ScrollDirection::eVertical))) ||
3363 (checkIfScrollableX && !checkIfScrollableY &&
3364 !(directions.contains(layers::ScrollDirection::eHorizontal)))) {
3365 continue;
3366 }
3367
3368 // Computes whether the currently checked frame is scrollable by this wheel
3369 // event.
3370 bool canScroll = false;
3371 if (isAutoDir) {
3372 ESMAutoDirWheelDeltaAdjuster adjuster(*aEvent, *scrollFrame, honoursRoot);
3373 if (adjuster.ShouldBeAdjusted()) {
3374 adjuster.Adjust();
3375 canScroll = true;
3376 } else if (WheelHandlingUtils::CanScrollOn(scrollContainerFrame,
3377 aDirectionX, aDirectionY)) {
3378 canScroll = true;
3379 }
3380 } else if (WheelHandlingUtils::CanScrollOn(scrollContainerFrame,
3381 aDirectionX, aDirectionY)) {
3382 canScroll = true;
3383 }
3384
3385 if (canScroll) {
3386 return scrollContainerFrame;
3387 }
3388
3389 // Where we are at is the block ending in a for loop.
3390 // The current frame has been checked to be unscrollable by this wheel
3391 // event, continue the loop to check its parent, if any.
3392 }
3393
3394 nsIFrame* newFrame = nsLayoutUtils::GetCrossDocParentFrameInProcess(
3395 aTargetFrame->PresShell()->GetRootFrame());
3396 aOptions =
3397 static_cast<ComputeScrollTargetOptions>(aOptions & ~START_FROM_PARENT);
3398 if (!newFrame) {
3399 return nullptr;
3400 }
3401 return ComputeScrollTargetAndMayAdjustWheelEvent(newFrame, aEvent, aOptions);
3402}
3403
3404nsSize EventStateManager::GetScrollAmount(
3405 nsPresContext* aPresContext, WidgetWheelEvent* aEvent,
3406 ScrollContainerFrame* aScrollContainerFrame) {
3407 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"
, 3407); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresContext"
")"); do { *((volatile int*)__null) = 3407; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3408 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"
, 3408); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 3408; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3409
3410 const bool isPage = aEvent->mDeltaMode == WheelEvent_Binding::DOM_DELTA_PAGE;
3411 if (!aScrollContainerFrame) {
3412 // If there is no scrollable frame, we should use root, see below.
3413 aScrollContainerFrame =
3414 aPresContext->PresShell()->GetRootScrollContainerFrame();
3415 }
3416
3417 if (aScrollContainerFrame) {
3418 return isPage ? aScrollContainerFrame->GetPageScrollAmount()
3419 : aScrollContainerFrame->GetLineScrollAmount();
3420 }
3421
3422 // If there is no scrollable frame and page scrolling, use viewport size.
3423 if (isPage) {
3424 return aPresContext->GetVisibleArea().Size();
3425 }
3426
3427 // Otherwise use root frame's font metrics.
3428 //
3429 // FIXME(emilio): Should this use the root element's style frame? The root
3430 // frame will always have the initial font. Then again it should never matter
3431 // for content, we should always have a root scrollable frame in html
3432 // documents.
3433 nsIFrame* rootFrame = aPresContext->PresShell()->GetRootFrame();
3434 if (!rootFrame) {
3435 return nsSize(0, 0);
3436 }
3437 RefPtr<nsFontMetrics> fm =
3438 nsLayoutUtils::GetInflatedFontMetricsForFrame(rootFrame);
3439 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"
, 3439); return nsSize(0, 0); } } while (false)
;
3440 return nsSize(fm->AveCharWidth(), fm->MaxHeight());
3441}
3442
3443void EventStateManager::DoScrollText(
3444 ScrollContainerFrame* aScrollContainerFrame, WidgetWheelEvent* aEvent) {
3445 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"
, 3445); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aScrollContainerFrame"
")"); do { *((volatile int*)__null) = 3445; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3446 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"
, 3446); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 3446; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3447
3448 AutoWeakFrame scrollFrameWeak(aScrollContainerFrame);
3449 AutoWeakFrame eventFrameWeak(mCurrentTarget);
3450 if (!WheelTransaction::WillHandleDefaultAction(aEvent, scrollFrameWeak,
3451 eventFrameWeak)) {
3452 return;
3453 }
3454
3455 // Default action's actual scroll amount should be computed from device
3456 // pixels.
3457 nsPresContext* pc = aScrollContainerFrame->PresContext();
3458 nsSize scrollAmount = GetScrollAmount(pc, aEvent, aScrollContainerFrame);
3459 nsIntSize scrollAmountInDevPixels(
3460 pc->AppUnitsToDevPixels(scrollAmount.width),
3461 pc->AppUnitsToDevPixels(scrollAmount.height));
3462 nsIntPoint actualDevPixelScrollAmount =
3463 DeltaAccumulator::GetInstance()->ComputeScrollAmountForDefaultAction(
3464 aEvent, scrollAmountInDevPixels);
3465
3466 // Don't scroll around the axis whose overflow style is hidden.
3467 ScrollStyles overflowStyle = aScrollContainerFrame->GetScrollStyles();
3468 if (overflowStyle.mHorizontal == StyleOverflow::Hidden) {
3469 actualDevPixelScrollAmount.x = 0;
3470 }
3471 if (overflowStyle.mVertical == StyleOverflow::Hidden) {
3472 actualDevPixelScrollAmount.y = 0;
3473 }
3474
3475 ScrollSnapFlags snapFlags = ScrollSnapFlags::Disabled;
3476 mozilla::ScrollOrigin origin = mozilla::ScrollOrigin::NotSpecified;
3477 switch (aEvent->mDeltaMode) {
3478 case WheelEvent_Binding::DOM_DELTA_LINE:
3479 origin = mozilla::ScrollOrigin::MouseWheel;
3480 snapFlags = ScrollSnapFlags::IntendedDirection;
3481 break;
3482 case WheelEvent_Binding::DOM_DELTA_PAGE:
3483 origin = mozilla::ScrollOrigin::Pages;
3484 snapFlags = ScrollSnapFlags::IntendedDirection |
3485 ScrollSnapFlags::IntendedEndPosition;
3486 break;
3487 case WheelEvent_Binding::DOM_DELTA_PIXEL:
3488 origin = mozilla::ScrollOrigin::Pixels;
3489 break;
3490 default:
3491 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"
, 3491); AnnotateMozCrashReason("MOZ_CRASH(" "Invalid deltaMode value comes"
")"); do { *((volatile int*)__null) = 3491; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
3492 }
3493
3494 // We shouldn't scroll more one page at once except when over one page scroll
3495 // is allowed for the event.
3496 nsSize pageSize = aScrollContainerFrame->GetPageScrollAmount();
3497 nsIntSize devPixelPageSize(pc->AppUnitsToDevPixels(pageSize.width),
3498 pc->AppUnitsToDevPixels(pageSize.height));
3499 if (!WheelPrefs::GetInstance()->IsOverOnePageScrollAllowedX(aEvent) &&
3500 DeprecatedAbs(actualDevPixelScrollAmount.x.value) >
3501 devPixelPageSize.width) {
3502 actualDevPixelScrollAmount.x = (actualDevPixelScrollAmount.x >= 0)
3503 ? devPixelPageSize.width
3504 : -devPixelPageSize.width;
3505 }
3506
3507 if (!WheelPrefs::GetInstance()->IsOverOnePageScrollAllowedY(aEvent) &&
3508 DeprecatedAbs(actualDevPixelScrollAmount.y.value) >
3509 devPixelPageSize.height) {
3510 actualDevPixelScrollAmount.y = (actualDevPixelScrollAmount.y >= 0)
3511 ? devPixelPageSize.height
3512 : -devPixelPageSize.height;
3513 }
3514
3515 bool isDeltaModePixel =
3516 (aEvent->mDeltaMode == WheelEvent_Binding::DOM_DELTA_PIXEL);
3517
3518 ScrollMode mode;
3519 switch (aEvent->mScrollType) {
3520 case WidgetWheelEvent::SCROLL_DEFAULT:
3521 if (isDeltaModePixel) {
3522 mode = ScrollMode::Normal;
3523 } else if (aEvent->mFlags.mHandledByAPZ) {
3524 mode = ScrollMode::SmoothMsd;
3525 } else {
3526 mode = ScrollMode::Smooth;
3527 }
3528 break;
3529 case WidgetWheelEvent::SCROLL_SYNCHRONOUSLY:
3530 mode = ScrollMode::Instant;
3531 break;
3532 case WidgetWheelEvent::SCROLL_ASYNCHRONOUSLY:
3533 mode = ScrollMode::Normal;
3534 break;
3535 case WidgetWheelEvent::SCROLL_SMOOTHLY:
3536 mode = ScrollMode::Smooth;
3537 break;
3538 default:
3539 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"
, 3539); AnnotateMozCrashReason("MOZ_CRASH(" "Invalid mScrollType value comes"
")"); do { *((volatile int*)__null) = 3539; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
3540 }
3541
3542 ScrollContainerFrame::ScrollMomentum momentum =
3543 aEvent->mIsMomentum ? ScrollContainerFrame::SYNTHESIZED_MOMENTUM_EVENT
3544 : ScrollContainerFrame::NOT_MOMENTUM;
3545
3546 nsIntPoint overflow;
3547 aScrollContainerFrame->ScrollBy(actualDevPixelScrollAmount,
3548 ScrollUnit::DEVICE_PIXELS, mode, &overflow,
3549 origin, momentum, snapFlags);
3550
3551 if (!scrollFrameWeak.IsAlive()) {
3552 // If the scroll causes changing the layout, we can think that the event
3553 // has been completely consumed by the content. Then, users probably don't
3554 // want additional action.
3555 aEvent->mOverflowDeltaX = aEvent->mOverflowDeltaY = 0;
3556 } else if (isDeltaModePixel) {
3557 aEvent->mOverflowDeltaX = overflow.x;
3558 aEvent->mOverflowDeltaY = overflow.y;
3559 } else {
3560 aEvent->mOverflowDeltaX =
3561 static_cast<double>(overflow.x) / scrollAmountInDevPixels.width;
3562 aEvent->mOverflowDeltaY =
3563 static_cast<double>(overflow.y) / scrollAmountInDevPixels.height;
3564 }
3565
3566 // If CSS overflow properties caused not to scroll, the overflowDelta* values
3567 // should be same as delta* values since they may be used as gesture event by
3568 // widget. However, if there is another scrollable element in the ancestor
3569 // along the axis, probably users don't want the operation to cause
3570 // additional action such as moving history. In such case, overflowDelta
3571 // values should stay zero.
3572 if (scrollFrameWeak.IsAlive()) {
3573 if (aEvent->mDeltaX && overflowStyle.mHorizontal == StyleOverflow::Hidden &&
3574 !ComputeScrollTargetAndMayAdjustWheelEvent(
3575 aScrollContainerFrame, aEvent,
3576 COMPUTE_SCROLLABLE_ANCESTOR_ALONG_X_AXIS_WITH_AUTO_DIR)) {
3577 aEvent->mOverflowDeltaX = aEvent->mDeltaX;
3578 }
3579 if (aEvent->mDeltaY && overflowStyle.mVertical == StyleOverflow::Hidden &&
3580 !ComputeScrollTargetAndMayAdjustWheelEvent(
3581 aScrollContainerFrame, aEvent,
3582 COMPUTE_SCROLLABLE_ANCESTOR_ALONG_Y_AXIS_WITH_AUTO_DIR)) {
3583 aEvent->mOverflowDeltaY = aEvent->mDeltaY;
3584 }
3585 }
3586
3587 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"
, 3590); MOZ_PretendNoReturn(); } } while (0)
3588 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"
, 3590); MOZ_PretendNoReturn(); } } while (0)
3589 (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"
, 3590); MOZ_PretendNoReturn(); } } while (0)
3590 "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"
, 3590); MOZ_PretendNoReturn(); } } while (0)
;
3591 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"
, 3594); MOZ_PretendNoReturn(); } } while (0)
3592 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"
, 3594); MOZ_PretendNoReturn(); } } while (0)
3593 (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"
, 3594); MOZ_PretendNoReturn(); } } while (0)
3594 "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"
, 3594); MOZ_PretendNoReturn(); } } while (0)
;
3595
3596 WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(aEvent);
3597}
3598
3599void EventStateManager::DecideGestureEvent(WidgetGestureNotifyEvent* aEvent,
3600 nsIFrame* targetFrame) {
3601 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"
, 3602); MOZ_PretendNoReturn(); } } while (0)
3602 "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"
, 3602); MOZ_PretendNoReturn(); } } while (0)
;
3603
3604 /* Check the ancestor tree to decide if any frame is willing* to receive
3605 * a MozPixelScroll event. If that's the case, the current touch gesture
3606 * will be used as a pan gesture; otherwise it will be a regular
3607 * mousedown/mousemove/click event.
3608 *
3609 * *willing: determine if it makes sense to pan the element using scroll
3610 * events:
3611 * - For web content: if there are any visible scrollbars on the touch point
3612 * - For XUL: if it's an scrollable element that can currently scroll in some
3613 * direction.
3614 *
3615 * Note: we'll have to one-off various cases to ensure a good usable behavior
3616 */
3617 WidgetGestureNotifyEvent::PanDirection panDirection =
3618 WidgetGestureNotifyEvent::ePanNone;
3619 bool displayPanFeedback = false;
3620 for (nsIFrame* current = targetFrame; current;
3621 current = nsLayoutUtils::GetCrossDocParentFrame(current)) {
3622 // e10s - mark remote content as pannable. This is a work around since
3623 // we don't have access to remote frame scroll info here. Apz data may
3624 // assist is solving this.
3625 if (current && IsTopLevelRemoteTarget(current->GetContent())) {
3626 panDirection = WidgetGestureNotifyEvent::ePanBoth;
3627 // We don't know when we reach bounds, so just disable feedback for now.
3628 displayPanFeedback = false;
3629 break;
3630 }
3631
3632 LayoutFrameType currentFrameType = current->Type();
3633
3634 // Scrollbars should always be draggable
3635 if (currentFrameType == LayoutFrameType::Scrollbar) {
3636 panDirection = WidgetGestureNotifyEvent::ePanNone;
3637 break;
3638 }
3639
3640 // Special check for trees
3641 if (nsTreeBodyFrame* treeFrame = do_QueryFrame(current)) {
3642 if (treeFrame->GetHorizontalOverflow()) {
3643 panDirection = WidgetGestureNotifyEvent::ePanHorizontal;
3644 }
3645 if (treeFrame->GetVerticalOverflow()) {
3646 panDirection = WidgetGestureNotifyEvent::ePanVertical;
3647 }
3648 break;
3649 }
3650
3651 if (ScrollContainerFrame* scrollContainerFrame = do_QueryFrame(current)) {
3652 layers::ScrollDirections scrollbarVisibility =
3653 scrollContainerFrame->GetScrollbarVisibility();
3654
3655 // Check if we have visible scrollbars
3656 if (scrollbarVisibility.contains(layers::ScrollDirection::eVertical)) {
3657 panDirection = WidgetGestureNotifyEvent::ePanVertical;
3658 displayPanFeedback = true;
3659 break;
3660 }
3661
3662 if (scrollbarVisibility.contains(layers::ScrollDirection::eHorizontal)) {
3663 panDirection = WidgetGestureNotifyEvent::ePanHorizontal;
3664 displayPanFeedback = true;
3665 }
3666 }
3667 } // ancestor chain
3668 aEvent->mDisplayPanFeedback = displayPanFeedback;
3669 aEvent->mPanDirection = panDirection;
3670}
3671
3672#ifdef XP_MACOSX
3673static nsINode* GetCrossDocParentNode(nsINode* aChild) {
3674 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"
, 3674); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild" ") ("
"The child is null!" ")"); do { *((volatile int*)__null) = 3674
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
3675 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"
, 3675); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 3675; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3676
3677 nsINode* parent = aChild->GetParentNode();
3678 if (parent && parent->IsContent() && aChild->IsContent()) {
3679 parent = aChild->AsContent()->GetFlattenedTreeParent();
3680 }
3681
3682 if (parent || !aChild->IsDocument()) {
3683 return parent;
3684 }
3685
3686 return aChild->AsDocument()->GetEmbedderElement();
3687}
3688
3689static bool NodeAllowsClickThrough(nsINode* aNode) {
3690 while (aNode) {
3691 if (aNode->IsAnyOfXULElements(nsGkAtoms::browser, nsGkAtoms::tree)) {
3692 return false;
3693 }
3694 if (aNode->IsAnyOfXULElements(nsGkAtoms::scrollbar, nsGkAtoms::resizer)) {
3695 return true;
3696 }
3697 aNode = GetCrossDocParentNode(aNode);
3698 }
3699 return true;
3700}
3701#endif
3702
3703void EventStateManager::PostHandleKeyboardEvent(
3704 WidgetKeyboardEvent* aKeyboardEvent, nsIFrame* aTargetFrame,
3705 nsEventStatus& aStatus) {
3706 if (aStatus == nsEventStatus_eConsumeNoDefault) {
3707 return;
3708 }
3709
3710 RefPtr<nsPresContext> presContext = mPresContext;
3711
3712 if (!aKeyboardEvent->HasBeenPostedToRemoteProcess()) {
3713 if (aKeyboardEvent->IsWaitingReplyFromRemoteProcess()) {
3714 RefPtr<BrowserParent> remote =
3715 aTargetFrame ? BrowserParent::GetFrom(aTargetFrame->GetContent())
3716 : nullptr;
3717 if (remote) {
3718 // remote is null-checked above in order to let pre-existing event
3719 // targeting code's chrome vs. content decision override in case of
3720 // disagreement in order not to disrupt non-Fission e10s mode in case
3721 // there are still bugs in the Fission-mode code. That is, if remote
3722 // is nullptr, the pre-existing event targeting code has deemed this
3723 // event to belong to chrome rather than content.
3724 BrowserParent* preciseRemote = BrowserParent::GetFocused();
3725 if (preciseRemote) {
3726 remote = preciseRemote;
3727 }
3728 // else there was a race between layout and focus tracking
3729 }
3730 if (remote && !remote->IsReadyToHandleInputEvents()) {
3731 // We need to dispatch the event to the browser element again if we were
3732 // waiting for the key reply but the event wasn't sent to the content
3733 // process due to the remote browser wasn't ready.
3734 WidgetKeyboardEvent keyEvent(*aKeyboardEvent);
3735 aKeyboardEvent->MarkAsHandledInRemoteProcess();
3736 RefPtr<Element> ownerElement = remote->GetOwnerElement();
3737 EventDispatcher::Dispatch(ownerElement, presContext, &keyEvent);
3738 if (keyEvent.DefaultPrevented()) {
3739 aKeyboardEvent->PreventDefault(!keyEvent.DefaultPreventedByContent());
3740 aStatus = nsEventStatus_eConsumeNoDefault;
3741 return;
3742 }
3743 }
3744 }
3745 // The widget expects a reply for every keyboard event. If the event wasn't
3746 // dispatched to a content process (non-e10s or no content process
3747 // running), we need to short-circuit here. Otherwise, we need to wait for
3748 // the content process to handle the event.
3749 if (aKeyboardEvent->mWidget) {
3750 aKeyboardEvent->mWidget->PostHandleKeyEvent(aKeyboardEvent);
3751 }
3752 if (aKeyboardEvent->DefaultPrevented()) {
3753 aStatus = nsEventStatus_eConsumeNoDefault;
3754 return;
3755 }
3756 }
3757
3758 // XXX Currently, our automated tests don't support mKeyNameIndex.
3759 // Therefore, we still need to handle this with keyCode.
3760 switch (aKeyboardEvent->mKeyCode) {
3761 case NS_VK_TAB:
3762 case NS_VK_F6:
3763 // This is to prevent keyboard scrolling while alt modifier in use.
3764 if (!aKeyboardEvent->IsAlt()) {
3765 aStatus = nsEventStatus_eConsumeNoDefault;
3766
3767 // Handling the tab event after it was sent to content is bad,
3768 // because to the FocusManager the remote-browser looks like one
3769 // element, so we would just move the focus to the next element
3770 // in chrome, instead of handling it in content.
3771 if (aKeyboardEvent->HasBeenPostedToRemoteProcess()) {
3772 break;
3773 }
3774
3775 EnsureDocument(presContext);
3776 nsFocusManager* fm = nsFocusManager::GetFocusManager();
3777 if (fm && mDocument) {
3778 // Shift focus forward or back depending on shift key
3779 bool isDocMove = aKeyboardEvent->IsControl() ||
3780 aKeyboardEvent->mKeyCode == NS_VK_F6;
3781 uint32_t dir =
3782 aKeyboardEvent->IsShift()
3783 ? (isDocMove ? static_cast<uint32_t>(
3784 nsIFocusManager::MOVEFOCUS_BACKWARDDOC)
3785 : static_cast<uint32_t>(
3786 nsIFocusManager::MOVEFOCUS_BACKWARD))
3787 : (isDocMove ? static_cast<uint32_t>(
3788 nsIFocusManager::MOVEFOCUS_FORWARDDOC)
3789 : static_cast<uint32_t>(
3790 nsIFocusManager::MOVEFOCUS_FORWARD));
3791 RefPtr<Element> result;
3792 fm->MoveFocus(mDocument->GetWindow(), nullptr, dir,
3793 nsIFocusManager::FLAG_BYKEY, getter_AddRefs(result));
3794 }
3795 }
3796 return;
3797 case 0:
3798 // We handle keys with no specific keycode value below.
3799 break;
3800 default:
3801 return;
3802 }
3803
3804 switch (aKeyboardEvent->mKeyNameIndex) {
3805 case KEY_NAME_INDEX_ZoomIn:
3806 case KEY_NAME_INDEX_ZoomOut:
3807 ChangeZoom(aKeyboardEvent->mKeyNameIndex == KEY_NAME_INDEX_ZoomIn);
3808 aStatus = nsEventStatus_eConsumeNoDefault;
3809 break;
3810 default:
3811 break;
3812 }
3813}
3814
3815static bool NeedsActiveContentChange(const WidgetMouseEvent* aMouseEvent) {
3816 // If the mouse event is a synthesized mouse event due to a touch, do
3817 // not set/clear the activation state. Element activation is handled by APZ.
3818 return !aMouseEvent ||
3819 aMouseEvent->mInputSource != MouseEvent_Binding::MOZ_SOURCE_TOUCH;
3820}
3821
3822nsresult EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
3823 WidgetEvent* aEvent,
3824 nsIFrame* aTargetFrame,
3825 nsEventStatus* aStatus,
3826 nsIContent* aOverrideClickTarget) {
3827 AUTO_PROFILER_LABEL("EventStateManager::PostHandleEvent", DOM)mozilla::AutoProfilerLabel raiiObject3827( "EventStateManager::PostHandleEvent"
, nullptr, JS::ProfilingCategoryPair::DOM)
;
3828 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"
, 3828); return NS_ERROR_INVALID_ARG; } } while (false)
;
1
Assuming 'aPresContext' is non-null
2
Taking false branch
3
Loop condition is false. Exiting loop
3829 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"
, 3829); return NS_ERROR_INVALID_POINTER; } } while (false)
;
4
Assuming 'aStatus' is non-null
5
Taking false branch
6
Loop condition is false. Exiting loop
3830
3831 mCurrentTarget = aTargetFrame;
3832 mCurrentTargetContent = nullptr;
3833
3834 HandleCrossProcessEvent(aEvent, aStatus);
3835 // NOTE: the above call may have destroyed aTargetFrame, please use
3836 // mCurrentTarget henceforth. This is to avoid using it accidentally:
3837 aTargetFrame = nullptr;
3838
3839 // Most of the events we handle below require a frame.
3840 // Add special cases here.
3841 if (!mCurrentTarget && aEvent->mMessage != eMouseUp &&
7
Assuming the condition is false
3842 aEvent->mMessage != eMouseDown && aEvent->mMessage != eDragEnter &&
3843 aEvent->mMessage != eDragOver && aEvent->mMessage != ePointerUp &&
3844 aEvent->mMessage != ePointerCancel) {
3845 return NS_OK;
3846 }
3847
3848 // Keep the prescontext alive, we might need it after event dispatch
3849 RefPtr<nsPresContext> presContext = aPresContext;
3850 nsresult ret = NS_OK;
3851
3852 switch (aEvent->mMessage) {
8
Control jumps to 'case ePointerUp:' at line 4069
3853 case eMouseDown: {
3854 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
3855 if (mouseEvent->mButton == MouseButton::ePrimary &&
3856 !sNormalLMouseEventInProcess) {
3857 // We got a mouseup event while a mousedown event was being processed.
3858 // Make sure that the capturing content is cleared.
3859 PresShell::ReleaseCapturingContent();
3860 break;
3861 }
3862
3863 // For remote content, capture the event in the parent process at the
3864 // <xul:browser remote> element. This will ensure that subsequent
3865 // mousemove/mouseup events will continue to be dispatched to this element
3866 // and therefore forwarded to the child.
3867 if (aEvent->HasBeenPostedToRemoteProcess() &&
3868 !PresShell::GetCapturingContent()) {
3869 if (nsIContent* content =
3870 mCurrentTarget ? mCurrentTarget->GetContent() : nullptr) {
3871 PresShell::SetCapturingContent(content, CaptureFlags::None, aEvent);
3872 } else {
3873 PresShell::ReleaseCapturingContent();
3874 }
3875 }
3876
3877 // If MouseEvent::PreventClickEvent() was called by chrome script,
3878 // we need to forget the clicking content and click count for the
3879 // following eMouseUp event.
3880 if (mouseEvent->mClickEventPrevented) {
3881 switch (mouseEvent->mButton) {
3882 case MouseButton::ePrimary:
3883 case MouseButton::eSecondary:
3884 case MouseButton::eMiddle: {
3885 LastMouseDownInfo& mouseDownInfo =
3886 GetLastMouseDownInfo(mouseEvent->mButton);
3887 mouseDownInfo.mLastMouseDownContent = nullptr;
3888 mouseDownInfo.mClickCount = 0;
3889 mouseDownInfo.mLastMouseDownInputControlType = Nothing();
3890 break;
3891 }
3892
3893 default:
3894 break;
3895 }
3896 }
3897
3898 nsCOMPtr<nsIContent> activeContent;
3899 // When content calls PreventDefault on pointerdown, we also call
3900 // PreventDefault on the subsequent mouse events to suppress default
3901 // behaviors. Normally, aStatus should be nsEventStatus_eConsumeNoDefault
3902 // when the event is DefaultPrevented but it's reset to
3903 // nsEventStatus_eIgnore in EventStateManager::PreHandleEvent. So we also
3904 // check if the event is DefaultPrevented.
3905 if (nsEventStatus_eConsumeNoDefault != *aStatus &&
3906 !aEvent->DefaultPrevented()) {
3907 nsCOMPtr<nsIContent> newFocus;
3908 bool suppressBlur = false;
3909 if (mCurrentTarget) {
3910 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(newFocus));
3911 activeContent = mCurrentTarget->GetContent();
3912
3913 // In some cases, we do not want to even blur the current focused
3914 // element. Those cases are:
3915 // 1. -moz-user-focus CSS property is set to 'ignore';
3916 // 2. XUL control element has the disabled property set to 'true'.
3917 //
3918 // We can't use nsIFrame::IsFocusable() because we want to blur when
3919 // we click on a visibility: none element.
3920 // We can't use nsIContent::IsFocusable() because we want to blur when
3921 // we click on a non-focusable element like a <div>.
3922 // We have to use |aEvent->mTarget| to not make sure we do not check
3923 // an anonymous node of the targeted element.
3924 suppressBlur =
3925 mCurrentTarget->StyleUI()->UserFocus() == StyleUserFocus::Ignore;
3926
3927 if (!suppressBlur) {
3928 if (Element* element =
3929 Element::FromEventTargetOrNull(aEvent->mTarget)) {
3930 if (nsCOMPtr<nsIDOMXULControlElement> xulControl =
3931 element->AsXULControl()) {
3932 bool disabled = false;
3933 xulControl->GetDisabled(&disabled);
3934 suppressBlur = disabled;
3935 }
3936 }
3937 }
3938 }
3939
3940 // When a root content which isn't editable but has an editable HTML
3941 // <body> element is clicked, we should redirect the focus to the
3942 // the <body> element. E.g., when an user click bottom of the editor
3943 // where is outside of the <body> element, the <body> should be focused
3944 // and the user can edit immediately after that.
3945 //
3946 // NOTE: The newFocus isn't editable that also means it's not in
3947 // designMode. In designMode, all contents are not focusable.
3948 if (newFocus && !newFocus->IsEditable()) {
3949 Document* doc = newFocus->GetComposedDoc();
3950 if (doc && newFocus == doc->GetRootElement()) {
3951 nsIContent* bodyContent =
3952 nsLayoutUtils::GetEditableRootContentByContentEditable(doc);
3953 if (bodyContent && bodyContent->GetPrimaryFrame()) {
3954 newFocus = bodyContent;
3955 }
3956 }
3957 }
3958
3959 // When the mouse is pressed, the default action is to focus the
3960 // target. Look for the nearest enclosing focusable frame.
3961 //
3962 // TODO: Probably this should be moved to Element::PostHandleEvent.
3963 for (; newFocus; newFocus = newFocus->GetFlattenedTreeParent()) {
3964 if (!newFocus->IsElement()) {
3965 continue;
3966 }
3967
3968 nsIFrame* frame = newFocus->GetPrimaryFrame();
3969 if (!frame) {
3970 continue;
3971 }
3972
3973 // If the mousedown happened inside a popup, don't try to set focus on
3974 // one of its containing elements
3975 if (frame->IsMenuPopupFrame()) {
3976 newFocus = nullptr;
3977 break;
3978 }
3979
3980 auto flags = IsFocusableFlags::WithMouse;
3981 if (frame->IsFocusable(flags)) {
3982 break;
3983 }
3984
3985 if (ShadowRoot* root = newFocus->GetShadowRoot()) {
3986 if (root->DelegatesFocus()) {
3987 if (Element* firstFocusable = root->GetFocusDelegate(flags)) {
3988 newFocus = firstFocusable;
3989 break;
3990 }
3991 }
3992 }
3993 }
3994
3995 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"
, 3995); AnnotateMozCrashReason("MOZ_ASSERT" "(" "newFocus->IsElement()"
")"); do { *((volatile int*)__null) = 3995; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
3996
3997 if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
3998 // if something was found to focus, focus it. Otherwise, if the
3999 // element that was clicked doesn't have -moz-user-focus: ignore,
4000 // clear the existing focus. For -moz-user-focus: ignore, the focus
4001 // is just left as is.
4002 // Another effect of mouse clicking, handled in Selection, is that
4003 // it should update the caret position to where the mouse was
4004 // clicked. Because the focus is cleared when clicking on a
4005 // non-focusable node, the next press of the tab key will cause
4006 // focus to be shifted from the caret position instead of the root.
4007 if (newFocus) {
4008 // use the mouse flag and the noscroll flag so that the content
4009 // doesn't unexpectedly scroll when clicking an element that is
4010 // only half visible
4011 uint32_t flags =
4012 nsIFocusManager::FLAG_BYMOUSE | nsIFocusManager::FLAG_NOSCROLL;
4013 // If this was a touch-generated event, pass that information:
4014 if (mouseEvent->mInputSource ==
4015 MouseEvent_Binding::MOZ_SOURCE_TOUCH) {
4016 flags |= nsIFocusManager::FLAG_BYTOUCH;
4017 }
4018 fm->SetFocus(MOZ_KnownLive(newFocus->AsElement())(newFocus->AsElement()), flags);
4019 } else if (!suppressBlur) {
4020 // clear the focus within the frame and then set it as the
4021 // focused frame
4022 EnsureDocument(mPresContext);
4023 if (mDocument) {
4024 nsCOMPtr<nsPIDOMWindowOuter> outerWindow = mDocument->GetWindow();
4025#ifdef XP_MACOSX
4026 if (!activeContent || !activeContent->IsXULElement())
4027#endif
4028 fm->ClearFocus(outerWindow);
4029 // Prevent switch frame if we're already not in the foreground tab
4030 // and we're in a content process.
4031 // TODO: If we were inactive frame in this tab, and now in
4032 // background tab, we shouldn't make the tab foreground, but
4033 // we should set focus to clicked document in the background
4034 // tab. However, nsFocusManager does not have proper method
4035 // for doing this. Therefore, we should skip setting focus
4036 // to clicked document for now.
4037 if (XRE_IsParentProcess() || IsInActiveTab(mDocument)) {
4038 fm->SetFocusedWindow(outerWindow);
4039 }
4040 }
4041 }
4042 }
4043
4044 // The rest is left button-specific.
4045 if (mouseEvent->mButton != MouseButton::ePrimary) {
4046 break;
4047 }
4048
4049 // The nearest enclosing element goes into the :active state. If we're
4050 // not an element (so we're text or something) we need to obtain
4051 // our parent element and put it into :active instead.
4052 if (activeContent && !activeContent->IsElement()) {
4053 if (nsIContent* par = activeContent->GetFlattenedTreeParent()) {
4054 activeContent = par;
4055 }
4056 }
4057 } else {
4058 // if we're here, the event handler returned false, so stop
4059 // any of our own processing of a drag. Workaround for bug 43258.
4060 StopTrackingDragGesture(true);
4061 }
4062 // XXX Why do we always set this is active? Active window may be changed
4063 // by a mousedown event listener.
4064 if (NeedsActiveContentChange(mouseEvent)) {
4065 SetActiveManager(this, activeContent);
4066 }
4067 } break;
4068 case ePointerCancel:
4069 case ePointerUp: {
4070 WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent();
4071 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"
, 4071); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pointerEvent"
")"); do { *((volatile int*)__null) = 4071; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9
Assuming 'pointerEvent' is non-null
10
Taking false branch
11
Loop condition is false. Exiting loop
4072 // Implicitly releasing capture for given pointer. ePointerLostCapture
4073 // should be send after ePointerUp or ePointerCancel.
4074 PointerEventHandler::ImplicitlyReleasePointerCapture(pointerEvent);
4075 PointerEventHandler::UpdateActivePointerState(pointerEvent);
4076
4077 if (
14
Taking true branch
4078 // After pointercancel, pointer becomes invalid so we can remove
4079 // relevant helper from table.
4080 pointerEvent->mMessage == ePointerCancel ||
12
Assuming field 'mMessage' is not equal to ePointerCancel
4081 // pointerup for non-hoverable pointer needs to dispatch pointerout
4082 // and pointerleave events because the pointer is valid only while the
4083 // pointer is "down".
4084 !pointerEvent->InputSourceSupportsHover()) {
13
Assuming the condition is true
4085 GenerateMouseEnterExit(pointerEvent);
15
Calling 'EventStateManager::GenerateMouseEnterExit'
4086 mPointersEnterLeaveHelper.Remove(pointerEvent->pointerId);
4087 }
4088
4089 break;
4090 }
4091 case eMouseUp: {
4092 // We can unconditionally stop capturing because
4093 // we should never be capturing when the mouse button is up
4094 PresShell::ReleaseCapturingContent();
4095
4096 WidgetMouseEvent* mouseUpEvent = aEvent->AsMouseEvent();
4097 if (NeedsActiveContentChange(mouseUpEvent)) {
4098 ClearGlobalActiveContent(this);
4099 }
4100 if (mouseUpEvent && EventCausesClickEvents(*mouseUpEvent)) {
4101 // Make sure to dispatch the click even if there is no frame for
4102 // the current target element. This is required for Web compatibility.
4103 RefPtr<EventStateManager> esm =
4104 ESMFromContentOrThis(aOverrideClickTarget);
4105 ret =
4106 esm->PostHandleMouseUp(mouseUpEvent, aStatus, aOverrideClickTarget);
4107 }
4108
4109 if (PresShell* presShell = presContext->GetPresShell()) {
4110 RefPtr<nsFrameSelection> frameSelection = presShell->FrameSelection();
4111 frameSelection->SetDragState(false);
4112 }
4113 } break;
4114 case eWheelOperationEnd: {
4115 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"
, 4115); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsTrusted()"
")"); do { *((volatile int*)__null) = 4115; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4116 ScrollbarsForWheel::MayInactivate();
4117 WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
4118 ScrollContainerFrame* scrollTarget =
4119 ComputeScrollTargetAndMayAdjustWheelEvent(
4120 mCurrentTarget, wheelEvent,
4121 COMPUTE_DEFAULT_ACTION_TARGET_WITH_AUTO_DIR);
4122 // If the wheel event was handled by APZ, APZ will perform the scroll
4123 // snap.
4124 if (scrollTarget && !WheelTransaction::HandledByApz()) {
4125 scrollTarget->ScrollSnap();
4126 }
4127 } break;
4128 case eWheel:
4129 case eWheelOperationStart: {
4130 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"
, 4130); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsTrusted()"
")"); do { *((volatile int*)__null) = 4130; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4131
4132 if (*aStatus == nsEventStatus_eConsumeNoDefault) {
4133 ScrollbarsForWheel::Inactivate();
4134 break;
4135 }
4136
4137 WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
4138 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"
, 4138); AnnotateMozCrashReason("MOZ_ASSERT" "(" "wheelEvent"
")"); do { *((volatile int*)__null) = 4138; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4139
4140 // When APZ is enabled, the actual scroll animation might be handled by
4141 // the compositor.
4142 WheelPrefs::Action action =
4143 wheelEvent->mFlags.mHandledByAPZ
4144 ? WheelPrefs::ACTION_NONE
4145 : WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent);
4146
4147 WheelDeltaAdjustmentStrategy strategy =
4148 GetWheelDeltaAdjustmentStrategy(*wheelEvent);
4149 // Adjust the delta values of the wheel event if the current default
4150 // action is to horizontalize scrolling. I.e., deltaY values are set to
4151 // deltaX and deltaY and deltaZ values are set to 0.
4152 // If horizontalized, the delta values will be restored and its overflow
4153 // deltaX will become 0 when the WheelDeltaHorizontalizer instance is
4154 // being destroyed.
4155 WheelDeltaHorizontalizer horizontalizer(*wheelEvent);
4156 if (WheelDeltaAdjustmentStrategy::eHorizontalize == strategy) {
4157 horizontalizer.Horizontalize();
4158 }
4159
4160 // Since ComputeScrollTargetAndMayAdjustWheelEvent() may adjust the delta
4161 // if the event is auto-dir. So we use |ESMAutoDirWheelDeltaRestorer|
4162 // here.
4163 // An instance of |ESMAutoDirWheelDeltaRestorer| is used to monitor
4164 // auto-dir adjustment which may happen during its lifetime. If the delta
4165 // values is adjusted during its lifetime, the instance will restore the
4166 // adjusted delta when it's being destrcuted.
4167 ESMAutoDirWheelDeltaRestorer restorer(*wheelEvent);
4168 ScrollContainerFrame* scrollTarget =
4169 ComputeScrollTargetAndMayAdjustWheelEvent(
4170 mCurrentTarget, wheelEvent,
4171 COMPUTE_DEFAULT_ACTION_TARGET_WITH_AUTO_DIR);
4172
4173 switch (action) {
4174 case WheelPrefs::ACTION_SCROLL:
4175 case WheelPrefs::ACTION_HORIZONTALIZED_SCROLL: {
4176 // For scrolling of default action, we should honor the mouse wheel
4177 // transaction.
4178
4179 ScrollbarsForWheel::PrepareToScrollText(this, mCurrentTarget,
4180 wheelEvent);
4181
4182 if (aEvent->mMessage != eWheel ||
4183 (!wheelEvent->mDeltaX && !wheelEvent->mDeltaY)) {
4184 break;
4185 }
4186
4187 ScrollbarsForWheel::SetActiveScrollTarget(scrollTarget);
4188
4189 ScrollContainerFrame* rootScrollContainerFrame =
4190 !mCurrentTarget
4191 ? nullptr
4192 : mCurrentTarget->PresShell()->GetRootScrollContainerFrame();
4193 if (!scrollTarget || scrollTarget == rootScrollContainerFrame) {
4194 wheelEvent->mViewPortIsOverscrolled = true;
4195 }
4196 wheelEvent->mOverflowDeltaX = wheelEvent->mDeltaX;
4197 wheelEvent->mOverflowDeltaY = wheelEvent->mDeltaY;
4198 WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(
4199 wheelEvent);
4200 if (scrollTarget) {
4201 DoScrollText(scrollTarget, wheelEvent);
4202 } else {
4203 WheelTransaction::EndTransaction();
4204 ScrollbarsForWheel::Inactivate();
4205 }
4206 break;
4207 }
4208 case WheelPrefs::ACTION_HISTORY: {
4209 // If this event doesn't cause eLegacyMouseLineOrPageScroll event or
4210 // the direction is oblique, don't perform history back/forward.
4211 int32_t intDelta = wheelEvent->GetPreferredIntDelta();
4212 if (!intDelta) {
4213 break;
4214 }
4215 DoScrollHistory(intDelta);
4216 break;
4217 }
4218 case WheelPrefs::ACTION_ZOOM: {
4219 // If this event doesn't cause eLegacyMouseLineOrPageScroll event or
4220 // the direction is oblique, don't perform zoom in/out.
4221 int32_t intDelta = wheelEvent->GetPreferredIntDelta();
4222 if (!intDelta) {
4223 break;
4224 }
4225 DoScrollZoom(mCurrentTarget, intDelta);
4226 break;
4227 }
4228 case WheelPrefs::ACTION_NONE:
4229 default:
4230 bool allDeltaOverflown = false;
4231 if (StaticPrefs::dom_event_wheel_event_groups_enabled() &&
4232 (wheelEvent->mDeltaX != 0.0 || wheelEvent->mDeltaY != 0.0)) {
4233 if (scrollTarget) {
4234 WheelTransaction::WillHandleDefaultAction(
4235 wheelEvent, scrollTarget, mCurrentTarget);
4236 } else {
4237 WheelTransaction::EndTransaction();
4238 }
4239 }
4240 if (wheelEvent->mFlags.mHandledByAPZ) {
4241 if (wheelEvent->mCanTriggerSwipe) {
4242 // For events that can trigger swipes, APZ needs to know whether
4243 // scrolling is possible in the requested direction. It does this
4244 // by looking at the scroll overflow values on mCanTriggerSwipe
4245 // events after they have been processed.
4246 allDeltaOverflown = !ComputeScrollTarget(
4247 mCurrentTarget, wheelEvent, COMPUTE_DEFAULT_ACTION_TARGET);
4248 }
4249 } else {
4250 // The event was processed neither by APZ nor by us, so all of the
4251 // delta values must be overflown delta values.
4252 allDeltaOverflown = true;
4253 }
4254
4255 if (!allDeltaOverflown) {
4256 break;
4257 }
4258 wheelEvent->mOverflowDeltaX = wheelEvent->mDeltaX;
4259 wheelEvent->mOverflowDeltaY = wheelEvent->mDeltaY;
4260 WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(
4261 wheelEvent);
4262 wheelEvent->mViewPortIsOverscrolled = true;
4263 break;
4264 }
4265 *aStatus = nsEventStatus_eConsumeNoDefault;
4266 } break;
4267
4268 case eGestureNotify: {
4269 if (nsEventStatus_eConsumeNoDefault != *aStatus) {
4270 DecideGestureEvent(aEvent->AsGestureNotifyEvent(), mCurrentTarget);
4271 }
4272 } break;
4273
4274 case eDragEnter:
4275 case eDragOver: {
4276 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"
, 4276); MOZ_PretendNoReturn(); } } while (0)
;
4277
4278 // Check if the drag is occurring inside a scrollable area. If so, scroll
4279 // the area when the mouse is near the edges.
4280 if (mCurrentTarget && aEvent->mMessage == eDragOver) {
4281 nsIFrame* checkFrame = mCurrentTarget;
4282 while (checkFrame) {
4283 ScrollContainerFrame* scrollFrame = do_QueryFrame(checkFrame);
4284 // Break out so only the innermost scrollframe is scrolled.
4285 if (scrollFrame && scrollFrame->DragScroll(aEvent)) {
4286 break;
4287 }
4288 checkFrame = checkFrame->GetParent();
4289 }
4290 }
4291
4292 nsCOMPtr<nsIDragSession> dragSession =
4293 nsContentUtils::GetDragSession(mPresContext);
4294 if (!dragSession) break;
4295
4296 // Reset the flag.
4297 dragSession->SetOnlyChromeDrop(false);
4298 if (mPresContext) {
4299 EnsureDocument(mPresContext);
4300 }
4301 bool isChromeDoc = nsContentUtils::IsChromeDoc(mDocument);
4302
4303 // the initial dataTransfer is the one from the dragstart event that
4304 // was set on the dragSession when the drag began.
4305 RefPtr<DataTransfer> dataTransfer;
4306 RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer();
4307
4308 WidgetDragEvent* dragEvent = aEvent->AsDragEvent();
4309
4310 // collect any changes to moz cursor settings stored in the event's
4311 // data transfer.
4312 UpdateDragDataTransfer(dragEvent);
4313
4314 // cancelling a dragenter or dragover event means that a drop should be
4315 // allowed, so update the dropEffect and the canDrop state to indicate
4316 // that a drag is allowed. If the event isn't cancelled, a drop won't be
4317 // allowed. Essentially, to allow a drop somewhere, specify the effects
4318 // using the effectAllowed and dropEffect properties in a dragenter or
4319 // dragover event and cancel the event. To not allow a drop somewhere,
4320 // don't cancel the event or set the effectAllowed or dropEffect to
4321 // "none". This way, if the event is just ignored, no drop will be
4322 // allowed.
4323 uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
4324 uint32_t action = nsIDragService::DRAGDROP_ACTION_NONE;
4325 if (nsEventStatus_eConsumeNoDefault == *aStatus) {
4326 // If the event has initialized its mDataTransfer, use it.
4327 // Or the event has not been initialized its mDataTransfer, but
4328 // it's set before dispatch because of synthesized, but without
4329 // testing session (e.g., emulating drag from another app), use it
4330 // coming from outside.
4331 // XXX Perhaps, for the latter case, we need new API because we don't
4332 // have a chance to initialize allowed effects of the session.
4333 if (dragEvent->mDataTransfer) {
4334 // get the dataTransfer and the dropEffect that was set on it
4335 dataTransfer = dragEvent->mDataTransfer;
4336 dropEffect = dataTransfer->DropEffectInt();
4337 } else {
4338 // if dragEvent->mDataTransfer is null, it means that no attempt was
4339 // made to access the dataTransfer during the event, yet the event
4340 // was cancelled. Instead, use the initial data transfer available
4341 // from the drag session. The drop effect would not have been
4342 // initialized (which is done in DragEvent::GetDataTransfer),
4343 // so set it from the drag action. We'll still want to filter it
4344 // based on the effectAllowed below.
4345 dataTransfer = initialDataTransfer;
4346
4347 dragSession->GetDragAction(&action);
4348
4349 // filter the drop effect based on the action. Use UNINITIALIZED as
4350 // any effect is allowed.
4351 dropEffect = nsContentUtils::FilterDropEffect(
4352 action, nsIDragService::DRAGDROP_ACTION_UNINITIALIZED);
4353 }
4354
4355 // At this point, if the dataTransfer is null, it means that the
4356 // drag was originally started by directly calling the drag service.
4357 // Just assume that all effects are allowed.
4358 uint32_t effectAllowed = nsIDragService::DRAGDROP_ACTION_UNINITIALIZED;
4359 if (dataTransfer) {
4360 effectAllowed = dataTransfer->EffectAllowedInt();
4361 }
4362
4363 // set the drag action based on the drop effect and effect allowed.
4364 // The drop effect field on the drag transfer object specifies the
4365 // desired current drop effect. However, it cannot be used if the
4366 // effectAllowed state doesn't include that type of action. If the
4367 // dropEffect is "none", then the action will be 'none' so a drop will
4368 // not be allowed.
4369 if (effectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED ||
4370 dropEffect & effectAllowed)
4371 action = dropEffect;
4372
4373 if (action == nsIDragService::DRAGDROP_ACTION_NONE)
4374 dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
4375
4376 // inform the drag session that a drop is allowed on this node.
4377 dragSession->SetDragAction(action);
4378 dragSession->SetCanDrop(action != nsIDragService::DRAGDROP_ACTION_NONE);
4379
4380 // For now, do this only for dragover.
4381 // XXXsmaug dragenter needs some more work.
4382 if (aEvent->mMessage == eDragOver && !isChromeDoc) {
4383 // Someone has called preventDefault(), check whether is was on
4384 // content or chrome.
4385 dragSession->SetOnlyChromeDrop(
4386 !dragEvent->mDefaultPreventedOnContent);
4387 }
4388 } else if (aEvent->mMessage == eDragOver && !isChromeDoc) {
4389 // No one called preventDefault(), so handle drop only in chrome.
4390 dragSession->SetOnlyChromeDrop(true);
4391 }
4392 if (auto* bc = BrowserChild::GetFrom(presContext->GetDocShell())) {
4393 bc->SendUpdateDropEffect(action, dropEffect);
4394 }
4395 if (aEvent->HasBeenPostedToRemoteProcess()) {
4396 dragSession->SetCanDrop(true);
4397 } else if (initialDataTransfer) {
4398 // Now set the drop effect in the initial dataTransfer. This ensures
4399 // that we can get the desired drop effect in the drop event. For events
4400 // dispatched to content, the content process will take care of setting
4401 // this.
4402 initialDataTransfer->SetDropEffectInt(dropEffect);
4403 }
4404 } break;
4405
4406 case eDrop: {
4407 if (aEvent->mFlags.mIsSynthesizedForTests) {
4408 nsCOMPtr<nsIDragService> dragService =
4409 do_GetService("@mozilla.org/widget/dragservice;1");
4410 nsCOMPtr<nsIDragSession> dragSession =
4411 nsContentUtils::GetDragSession(mPresContext);
4412 if (dragSession && dragService &&
4413 !dragService->GetNeverAllowSessionIsSynthesizedForTests()) {
4414 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"
, 4414); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dragSession->IsSynthesizedForTests()"
")"); do { *((volatile int*)__null) = 4414; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4415 RefPtr<WindowContext> sourceWC;
4416 DebugOnly<nsresult> rvIgnored =
4417 dragSession->GetSourceWindowContext(getter_AddRefs(sourceWC));
4418 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"
, 4420); } } while (false)
4419 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"
, 4420); } } while (false)
4420 "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"
, 4420); } } while (false)
;
4421 // If the drag source hasn't been initialized, i.e., dragstart was
4422 // consumed by the test, the test needs to dispatch "dragend" event
4423 // instead of the drag session. Therefore, it does not make sense
4424 // to set drag end point in such case (you hit assersion if you do
4425 // it).
4426 if (sourceWC) {
4427 CSSIntPoint dropPointInScreen =
4428 Event::GetScreenCoords(aPresContext, aEvent, aEvent->mRefPoint)
4429 .extract();
4430 dragSession->SetDragEndPointForTests(dropPointInScreen.x,
4431 dropPointInScreen.y);
4432 }
4433 }
4434 }
4435 sLastDragOverFrame = nullptr;
4436 ClearGlobalActiveContent(this);
4437 break;
4438 }
4439 case eDragExit: {
4440 // make sure to fire the enter and exit_synth events after the
4441 // eDragExit event, otherwise we'll clean up too early
4442 GenerateDragDropEnterExit(presContext, aEvent->AsDragEvent());
4443 if (auto* bc = BrowserChild::GetFrom(presContext->GetDocShell())) {
4444 // SendUpdateDropEffect to prevent nsIDragService from waiting for
4445 // response of forwarded dragexit event.
4446 bc->SendUpdateDropEffect(nsIDragService::DRAGDROP_ACTION_NONE,
4447 nsIDragService::DRAGDROP_ACTION_NONE);
4448 }
4449 break;
4450 }
4451 case eKeyUp:
4452 // If space key is released, we need to inactivate the element which was
4453 // activated by preceding space key down.
4454 // XXX Currently, we don't store the reason of activation. Therefore,
4455 // this may cancel what is activated by a mousedown, but it must not
4456 // cause actual problem in web apps in the wild since it must be
4457 // rare case that users release space key during a mouse click/drag.
4458 if (aEvent->AsKeyboardEvent()->ShouldWorkAsSpaceKey()) {
4459 ClearGlobalActiveContent(this);
4460 }
4461 break;
4462
4463 case eKeyPress: {
4464 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
4465 PostHandleKeyboardEvent(keyEvent, mCurrentTarget, *aStatus);
4466 } break;
4467
4468 case eMouseEnterIntoWidget:
4469 if (mCurrentTarget) {
4470 nsCOMPtr<nsIContent> targetContent;
4471 mCurrentTarget->GetContentForEvent(aEvent,
4472 getter_AddRefs(targetContent));
4473 SetContentState(targetContent, ElementState::HOVER);
4474 }
4475 break;
4476
4477 case eMouseExitFromWidget:
4478 PointerEventHandler::UpdateActivePointerState(aEvent->AsMouseEvent());
4479 break;
4480
4481#ifdef XP_MACOSX
4482 case eMouseActivate:
4483 if (mCurrentTarget) {
4484 nsCOMPtr<nsIContent> targetContent;
4485 mCurrentTarget->GetContentForEvent(aEvent,
4486 getter_AddRefs(targetContent));
4487 if (!NodeAllowsClickThrough(targetContent)) {
4488 *aStatus = nsEventStatus_eConsumeNoDefault;
4489 }
4490 }
4491 break;
4492#endif
4493
4494 default:
4495 break;
4496 }
4497
4498 // Reset target frame to null to avoid mistargeting after reentrant event
4499 mCurrentTarget = nullptr;
4500 mCurrentTargetContent = nullptr;
4501
4502 return ret;
4503}
4504
4505BrowserParent* EventStateManager::GetCrossProcessTarget() {
4506 return IMEStateManager::GetActiveBrowserParent();
4507}
4508
4509bool EventStateManager::IsTargetCrossProcess(WidgetGUIEvent* aEvent) {
4510 // Check to see if there is a focused, editable content in chrome,
4511 // in that case, do not forward IME events to content
4512 Element* focusedElement = GetFocusedElement();
4513 if (focusedElement && focusedElement->IsEditable()) {
4514 return false;
4515 }
4516 return IMEStateManager::GetActiveBrowserParent() != nullptr;
4517}
4518
4519void EventStateManager::NotifyDestroyPresContext(nsPresContext* aPresContext) {
4520 RefPtr<nsPresContext> presContext = aPresContext;
4521 if (presContext) {
4522 IMEStateManager::OnDestroyPresContext(*presContext);
4523 }
4524
4525 // Bug 70855: Presentation is going away, possibly for a reframe.
4526 // Reset the hover state so that if we're recreating the presentation,
4527 // we won't have the old hover state still set in the new presentation,
4528 // as if the new presentation is resized, a new element may be hovered.
4529 ResetHoverState();
4530
4531 mMouseEnterLeaveHelper = nullptr;
4532 mPointersEnterLeaveHelper.Clear();
4533 PointerEventHandler::NotifyDestroyPresContext(presContext);
4534}
4535
4536void EventStateManager::ResetHoverState() {
4537 if (mHoverContent) {
4538 SetContentState(nullptr, ElementState::HOVER);
4539 }
4540}
4541
4542void EventStateManager::SetPresContext(nsPresContext* aPresContext) {
4543 mPresContext = aPresContext;
4544}
4545
4546void EventStateManager::ClearFrameRefs(nsIFrame* aFrame) {
4547 if (aFrame && aFrame == mCurrentTarget) {
4548 mCurrentTargetContent = aFrame->GetContent();
4549 }
4550}
4551
4552struct CursorImage {
4553 gfx::IntPoint mHotspot;
4554 nsCOMPtr<imgIContainer> mContainer;
4555 ImageResolution mResolution;
4556 bool mEarlierCursorLoading = false;
4557};
4558
4559// Given the event that we're processing, and the computed cursor and hotspot,
4560// determine whether the custom CSS cursor should be blocked (that is, not
4561// honored).
4562//
4563// We will not honor it all of the following are true:
4564//
4565// * the size of the custom cursor is bigger than layout.cursor.block.max-size.
4566// * the bounds of the cursor would end up outside of the viewport of the
4567// top-level content document.
4568//
4569// This is done in order to prevent hijacking the cursor, see bug 1445844 and
4570// co.
4571static bool ShouldBlockCustomCursor(nsPresContext* aPresContext,
4572 WidgetEvent* aEvent,
4573 const CursorImage& aCursor) {
4574 int32_t width = 0;
4575 int32_t height = 0;
4576 aCursor.mContainer->GetWidth(&width);
4577 aCursor.mContainer->GetHeight(&height);
4578 aCursor.mResolution.ApplyTo(width, height);
4579
4580 int32_t maxSize = StaticPrefs::layout_cursor_block_max_size();
4581
4582 if (width <= maxSize && height <= maxSize) {
4583 return false;
4584 }
4585
4586 auto input = DOMIntersectionObserver::ComputeInput(*aPresContext->Document(),
4587 nullptr, nullptr);
4588
4589 if (!input.mRootFrame) {
4590 return false;
4591 }
4592
4593 nsPoint point = nsLayoutUtils::GetEventCoordinatesRelativeTo(
4594 aEvent, RelativeTo{input.mRootFrame});
4595
4596 // The cursor size won't be affected by our full zoom in the parent process,
4597 // so undo that before checking the rect.
4598 float zoom = aPresContext->GetFullZoom();
4599
4600 // Also adjust for accessibility cursor scaling factor.
4601 zoom /= LookAndFeel::GetFloat(LookAndFeel::FloatID::CursorScale, 1.0f);
4602
4603 nsSize size(CSSPixel::ToAppUnits(width / zoom),
4604 CSSPixel::ToAppUnits(height / zoom));
4605 nsPoint hotspot(
4606 CSSPixel::ToAppUnits(ViewAs<CSSPixel>(aCursor.mHotspot.x / zoom)),
4607 CSSPixel::ToAppUnits(ViewAs<CSSPixel>(aCursor.mHotspot.y / zoom)));
4608
4609 const nsRect cursorRect(point - hotspot, size);
4610 auto output = DOMIntersectionObserver::Intersect(input, cursorRect);
4611 return !output.mIntersectionRect ||
4612 !(*output.mIntersectionRect == cursorRect);
4613}
4614
4615static gfx::IntPoint ComputeHotspot(imgIContainer* aContainer,
4616 const Maybe<gfx::Point>& aHotspot) {
4617 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"
, 4617); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContainer"
")"); do { *((volatile int*)__null) = 4617; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4618
4619 // css3-ui says to use the CSS-specified hotspot if present,
4620 // otherwise use the intrinsic hotspot, otherwise use the top left
4621 // corner.
4622 if (aHotspot) {
4623 int32_t imgWidth, imgHeight;
4624 aContainer->GetWidth(&imgWidth);
4625 aContainer->GetHeight(&imgHeight);
4626 auto hotspot = gfx::IntPoint::Round(*aHotspot);
4627 return {std::max(std::min(hotspot.x.value, imgWidth - 1), 0),
4628 std::max(std::min(hotspot.y.value, imgHeight - 1), 0)};
4629 }
4630
4631 gfx::IntPoint hotspot;
4632 aContainer->GetHotspotX(&hotspot.x.value);
4633 aContainer->GetHotspotY(&hotspot.y.value);
4634 return hotspot;
4635}
4636
4637static CursorImage ComputeCustomCursor(nsPresContext* aPresContext,
4638 WidgetEvent* aEvent,
4639 const nsIFrame& aFrame,
4640 const nsIFrame::Cursor& aCursor) {
4641 if (aCursor.mAllowCustomCursor == nsIFrame::AllowCustomCursorImage::No) {
4642 return {};
4643 }
4644 const ComputedStyle& style =
4645 aCursor.mStyle ? *aCursor.mStyle : *aFrame.Style();
4646
4647 // If we are falling back because any cursor before us is loading, let the
4648 // consumer know.
4649 bool loading = false;
4650 for (const auto& image : style.StyleUI()->Cursor().images.AsSpan()) {
4651 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"
, 4652); AnnotateMozCrashReason("MOZ_ASSERT" "(" "image.image.IsImageRequestType()"
") (" "Cursor image should only parse url() types" ")"); do {
*((volatile int*)__null) = 4652; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
4652 "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"
, 4652); AnnotateMozCrashReason("MOZ_ASSERT" "(" "image.image.IsImageRequestType()"
") (" "Cursor image should only parse url() types" ")"); do {
*((volatile int*)__null) = 4652; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
4653 uint32_t status;
4654 imgRequestProxy* req = image.image.GetImageRequest();
4655 if (!req || NS_FAILED(req->GetImageStatus(&status))((bool)(__builtin_expect(!!(NS_FAILED_impl(req->GetImageStatus
(&status))), 0)))
) {
4656 continue;
4657 }
4658 if (!(status & imgIRequest::STATUS_LOAD_COMPLETE)) {
4659 loading = true;
4660 continue;
4661 }
4662 if (status & imgIRequest::STATUS_ERROR) {
4663 continue;
4664 }
4665 nsCOMPtr<imgIContainer> container;
4666 req->GetImage(getter_AddRefs(container));
4667 if (!container) {
4668 continue;
4669 }
4670 StyleImageOrientation orientation =
4671 aFrame.StyleVisibility()->UsedImageOrientation(req);
4672 container = nsLayoutUtils::OrientImage(container, orientation);
4673 Maybe<gfx::Point> specifiedHotspot =
4674 image.has_hotspot ? Some(gfx::Point{image.hotspot_x, image.hotspot_y})
4675 : Nothing();
4676 gfx::IntPoint hotspot = ComputeHotspot(container, specifiedHotspot);
4677 CursorImage result{hotspot, std::move(container),
4678 image.image.GetResolution(style), loading};
4679 if (ShouldBlockCustomCursor(aPresContext, aEvent, result)) {
4680 continue;
4681 }
4682 // This is the one we want!
4683 return result;
4684 }
4685 return {{}, nullptr, {}, loading};
4686}
4687
4688void EventStateManager::UpdateCursor(nsPresContext* aPresContext,
4689 WidgetMouseEvent* aEvent,
4690 nsIFrame* aTargetFrame,
4691 nsEventStatus* aStatus) {
4692 if (aTargetFrame && IsRemoteTarget(aTargetFrame->GetContent())) {
4693 return;
4694 }
4695
4696 auto cursor = StyleCursorKind::Default;
4697 nsCOMPtr<imgIContainer> container;
4698 ImageResolution resolution;
4699 Maybe<gfx::IntPoint> hotspot;
4700
4701 if (mHidingCursorWhileTyping && aEvent->IsReal()) {
4702 // Any non-synthetic mouse event makes us show the cursor again.
4703 mHidingCursorWhileTyping = false;
4704 }
4705
4706 if (mHidingCursorWhileTyping) {
4707 cursor = StyleCursorKind::None;
4708 } else if (mLockCursor != kInvalidCursorKind) {
4709 // If cursor is locked just use the locked one
4710 cursor = mLockCursor;
4711 } else if (aTargetFrame) {
4712 // If not locked, look for correct cursor
4713 nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(
4714 aEvent, RelativeTo{aTargetFrame});
4715 const nsIFrame::Cursor framecursor = aTargetFrame->GetCursor(pt);
4716 const CursorImage customCursor =
4717 ComputeCustomCursor(aPresContext, aEvent, *aTargetFrame, framecursor);
4718
4719 // If the current cursor is from the same frame, and it is now
4720 // loading some new image for the cursor, we should wait for a
4721 // while rather than taking its fallback cursor directly.
4722 if (customCursor.mEarlierCursorLoading &&
4723 gLastCursorSourceFrame == aTargetFrame &&
4724 TimeStamp::NowLoRes() - gLastCursorUpdateTime <
4725 TimeDuration::FromMilliseconds(kCursorLoadingTimeout)) {
4726 return;
4727 }
4728 cursor = framecursor.mCursor;
4729 container = std::move(customCursor.mContainer);
4730 resolution = customCursor.mResolution;
4731 hotspot = Some(customCursor.mHotspot);
4732 }
4733
4734 if (aTargetFrame) {
4735 if (cursor == StyleCursorKind::Pointer && IsSelectingLink(aTargetFrame)) {
4736 cursor = aTargetFrame->GetWritingMode().IsVertical()
4737 ? StyleCursorKind::VerticalText
4738 : StyleCursorKind::Text;
4739 }
4740 SetCursor(cursor, container, resolution, hotspot,
4741 aTargetFrame->GetNearestWidget(), false);
4742 gLastCursorSourceFrame = aTargetFrame;
4743 gLastCursorUpdateTime = TimeStamp::NowLoRes();
4744 }
4745
4746 if (mLockCursor != kInvalidCursorKind || StyleCursorKind::Auto != cursor) {
4747 *aStatus = nsEventStatus_eConsumeDoDefault;
4748 }
4749}
4750
4751void EventStateManager::ClearCachedWidgetCursor(nsIFrame* aTargetFrame) {
4752 if (!aTargetFrame) {
4753 return;
4754 }
4755 nsIWidget* aWidget = aTargetFrame->GetNearestWidget();
4756 if (!aWidget) {
4757 return;
4758 }
4759 aWidget->ClearCachedCursor();
4760}
4761
4762void EventStateManager::StartHidingCursorWhileTyping(nsIWidget* aWidget) {
4763 if (mHidingCursorWhileTyping || sCursorSettingManager != this) {
4764 return;
4765 }
4766 mHidingCursorWhileTyping = true;
4767 SetCursor(StyleCursorKind::None, nullptr, {}, {}, aWidget, false);
4768}
4769
4770nsresult EventStateManager::SetCursor(StyleCursorKind aCursor,
4771 imgIContainer* aContainer,
4772 const ImageResolution& aResolution,
4773 const Maybe<gfx::IntPoint>& aHotspot,
4774 nsIWidget* aWidget, bool aLockCursor) {
4775 EnsureDocument(mPresContext);
4776 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"
, 4776); return NS_ERROR_FAILURE; } } while (false)
;
4777 sCursorSettingManager = this;
4778
4779 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"
, 4779); return NS_ERROR_FAILURE; } } while (false)
;
4780 if (aLockCursor) {
4781 if (StyleCursorKind::Auto != aCursor) {
4782 mLockCursor = aCursor;
4783 } else {
4784 // If cursor style is set to auto we unlock the cursor again.
4785 mLockCursor = kInvalidCursorKind;
4786 }
4787 }
4788 nsCursor c;
4789 switch (aCursor) {
4790 case StyleCursorKind::Auto:
4791 case StyleCursorKind::Default:
4792 c = eCursor_standard;
4793 break;
4794 case StyleCursorKind::Pointer:
4795 c = eCursor_hyperlink;
4796 break;
4797 case StyleCursorKind::Crosshair:
4798 c = eCursor_crosshair;
4799 break;
4800 case StyleCursorKind::Move:
4801 c = eCursor_move;
4802 break;
4803 case StyleCursorKind::Text:
4804 c = eCursor_select;
4805 break;
4806 case StyleCursorKind::Wait:
4807 c = eCursor_wait;
4808 break;
4809 case StyleCursorKind::Help:
4810 c = eCursor_help;
4811 break;
4812 case StyleCursorKind::NResize:
4813 c = eCursor_n_resize;
4814 break;
4815 case StyleCursorKind::SResize:
4816 c = eCursor_s_resize;
4817 break;
4818 case StyleCursorKind::WResize:
4819 c = eCursor_w_resize;
4820 break;
4821 case StyleCursorKind::EResize:
4822 c = eCursor_e_resize;
4823 break;
4824 case StyleCursorKind::NwResize:
4825 c = eCursor_nw_resize;
4826 break;
4827 case StyleCursorKind::SeResize:
4828 c = eCursor_se_resize;
4829 break;
4830 case StyleCursorKind::NeResize:
4831 c = eCursor_ne_resize;
4832 break;
4833 case StyleCursorKind::SwResize:
4834 c = eCursor_sw_resize;
4835 break;
4836 case StyleCursorKind::Copy: // CSS3
4837 c = eCursor_copy;
4838 break;
4839 case StyleCursorKind::Alias:
4840 c = eCursor_alias;
4841 break;
4842 case StyleCursorKind::ContextMenu:
4843 c = eCursor_context_menu;
4844 break;
4845 case StyleCursorKind::Cell:
4846 c = eCursor_cell;
4847 break;
4848 case StyleCursorKind::Grab:
4849 c = eCursor_grab;
4850 break;
4851 case StyleCursorKind::Grabbing:
4852 c = eCursor_grabbing;
4853 break;
4854 case StyleCursorKind::Progress:
4855 c = eCursor_spinning;
4856 break;
4857 case StyleCursorKind::ZoomIn:
4858 c = eCursor_zoom_in;
4859 break;
4860 case StyleCursorKind::ZoomOut:
4861 c = eCursor_zoom_out;
4862 break;
4863 case StyleCursorKind::NotAllowed:
4864 c = eCursor_not_allowed;
4865 break;
4866 case StyleCursorKind::ColResize:
4867 c = eCursor_col_resize;
4868 break;
4869 case StyleCursorKind::RowResize:
4870 c = eCursor_row_resize;
4871 break;
4872 case StyleCursorKind::NoDrop:
4873 c = eCursor_no_drop;
4874 break;
4875 case StyleCursorKind::VerticalText:
4876 c = eCursor_vertical_text;
4877 break;
4878 case StyleCursorKind::AllScroll:
4879 c = eCursor_all_scroll;
4880 break;
4881 case StyleCursorKind::NeswResize:
4882 c = eCursor_nesw_resize;
4883 break;
4884 case StyleCursorKind::NwseResize:
4885 c = eCursor_nwse_resize;
4886 break;
4887 case StyleCursorKind::NsResize:
4888 c = eCursor_ns_resize;
4889 break;
4890 case StyleCursorKind::EwResize:
4891 c = eCursor_ew_resize;
4892 break;
4893 case StyleCursorKind::None:
4894 c = eCursor_none;
4895 break;
4896 default:
4897 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"
, 4897); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unknown cursor kind" ")"); do { *
((volatile int*)__null) = 4897; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
4898 c = eCursor_standard;
4899 break;
4900 }
4901
4902 uint32_t x = aHotspot ? aHotspot->x.value : 0;
4903 uint32_t y = aHotspot ? aHotspot->y.value : 0;
4904 aWidget->SetCursor(nsIWidget::Cursor{c, aContainer, x, y, aResolution});
4905 return NS_OK;
4906}
4907
4908bool EventStateManager::CursorSettingManagerHasLockedCursor() {
4909 return sCursorSettingManager &&
4910 sCursorSettingManager->mLockCursor != kInvalidCursorKind;
4911}
4912
4913class MOZ_STACK_CLASS ESMEventCB : public EventDispatchingCallback {
4914 public:
4915 explicit ESMEventCB(nsIContent* aTarget) : mTarget(aTarget) {}
4916
4917 MOZ_CAN_RUN_SCRIPT
4918 void HandleEvent(EventChainPostVisitor& aVisitor) override {
4919 if (aVisitor.mPresContext) {
4920 nsIFrame* frame = aVisitor.mPresContext->GetPrimaryFrameFor(mTarget);
4921 if (frame) {
4922 frame->HandleEvent(aVisitor.mPresContext, aVisitor.mEvent->AsGUIEvent(),
4923 &aVisitor.mEventStatus);
4924 }
4925 }
4926 }
4927
4928 nsCOMPtr<nsIContent> mTarget;
4929};
4930
4931static UniquePtr<WidgetMouseEvent> CreateMouseOrPointerWidgetEvent(
4932 WidgetMouseEvent* aMouseEvent, EventMessage aMessage,
4933 EventTarget* aRelatedTarget) {
4934 // This method does not support creating a mouse/pointer button change event
4935 // because of no data about the changing state.
4936 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"
, 4936); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != eMouseDown"
")"); do { *((volatile int*)__null) = 4936; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4937 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"
, 4937); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != eMouseUp"
")"); do { *((volatile int*)__null) = 4937; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4938 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"
, 4938); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != ePointerDown"
")"); do { *((volatile int*)__null) = 4938; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4939 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"
, 4939); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != ePointerUp"
")"); do { *((volatile int*)__null) = 4939; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4940 // This method is currently designed to create the following events.
4941 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"
, 4946); 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) = 4946; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4942 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"
, 4946); 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) = 4946; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4943 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"
, 4946); 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) = 4946; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4944 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"
, 4946); 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) = 4946; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4945 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"
, 4946); 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) = 4946; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4946 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"
, 4946); 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) = 4946; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4947
4948 WidgetPointerEvent* sourcePointer = aMouseEvent->AsPointerEvent();
4949 UniquePtr<WidgetMouseEvent> newEvent;
4950 if (sourcePointer) {
4951 AUTO_PROFILER_LABEL("CreateMouseOrPointerWidgetEvent", OTHER)mozilla::AutoProfilerLabel raiiObject4951( "CreateMouseOrPointerWidgetEvent"
, nullptr, JS::ProfilingCategoryPair::OTHER)
;
4952
4953 WidgetPointerEvent* newPointerEvent = new WidgetPointerEvent(
4954 aMouseEvent->IsTrusted(), aMessage, aMouseEvent->mWidget);
4955 newPointerEvent->mIsPrimary = sourcePointer->mIsPrimary;
4956 newPointerEvent->mWidth = sourcePointer->mWidth;
4957 newPointerEvent->mHeight = sourcePointer->mHeight;
4958 newPointerEvent->mInputSource = sourcePointer->mInputSource;
4959
4960 newEvent = WrapUnique(newPointerEvent);
4961 } else {
4962 newEvent = MakeUnique<WidgetMouseEvent>(aMouseEvent->IsTrusted(), aMessage,
4963 aMouseEvent->mWidget,
4964 WidgetMouseEvent::eReal);
4965 }
4966
4967 // Inherit whether the event is synthesized by the test API or not.
4968 // Then, when the event is synthesized by a test API and handled in a remote
4969 // process, it won't be ignored. See PresShell::HandleEvent().
4970 newEvent->mFlags.mIsSynthesizedForTests =
4971 aMouseEvent->mFlags.mIsSynthesizedForTests;
4972
4973 newEvent->mRelatedTarget = aRelatedTarget;
4974 newEvent->mRefPoint = aMouseEvent->mRefPoint;
4975 newEvent->mModifiers = aMouseEvent->mModifiers;
4976 if (!aMouseEvent->mFlags.mDispatchedAtLeastOnce &&
4977 aMouseEvent->InputSourceSupportsHover()) {
4978 // If we synthesize a pointer event or a mouse event from another event
4979 // which changes a button state whose input soucre supports hover state and
4980 // the source event has not been dispatched yet, we should set to the button
4981 // state of the synthesizing event to previous one.
4982 // Note that we don't need to do this if the input source does not support
4983 // hover state because a WPT check the behavior (see below) and the other
4984 // browsers pass the test even though this is inconsistent behavior.
4985 newEvent->mButton =
4986 sourcePointer ? MouseButton::eNotPressed : MouseButton::ePrimary;
4987 if (aMouseEvent->IsPressingButton()) {
4988 // If the source event has not been dispatched into the DOM yet, we
4989 // need to remove the flag which is being pressed.
4990 newEvent->mButtons = static_cast<decltype(WidgetMouseEvent::mButtons)>(
4991 aMouseEvent->mButtons &
4992 ~MouseButtonsFlagToChange(
4993 static_cast<MouseButton>(aMouseEvent->mButton)));
4994 } else if (aMouseEvent->IsReleasingButton()) {
4995 // If the source event has not been dispatched into the DOM yet, we
4996 // need to add the flag which is being released.
4997 newEvent->mButtons = static_cast<decltype(WidgetMouseEvent::mButtons)>(
4998 aMouseEvent->mButtons |
4999 MouseButtonsFlagToChange(
5000 static_cast<MouseButton>(aMouseEvent->mButton)));
5001 } else {
5002 // The source event does not change the buttons state so that we can
5003 // set mButtons value as-is.
5004 newEvent->mButtons = aMouseEvent->mButtons;
5005 }
5006 // Adjust pressure if it does not matches with mButtons.
5007 // FIXME: We may use wrong pressure value if the source event has not been
5008 // dispatched into the DOM yet. However, fixing this requires to store the
5009 // last pressure value somewhere.
5010 if (newEvent->mButtons && aMouseEvent->mPressure == 0) {
5011 newEvent->mPressure = 0.5f;
5012 } else if (!newEvent->mButtons && aMouseEvent->mPressure != 0) {
5013 newEvent->mPressure = 0;
5014 } else {
5015 newEvent->mPressure = aMouseEvent->mPressure;
5016 }
5017 } else {
5018 // If the event has already been dispatched into the tree, web apps has
5019 // already handled the button state change, so the button state of the
5020 // source event has already synced.
5021 // If the input source does not have hover state, we don't need to modify
5022 // the state because the other browsers behave so and tested by
5023 // pointerevent_attributes_nohover_pointers.html even though this is
5024 // different expectation from
5025 // pointerevent_attributes_hoverable_pointers.html, but the other browsers
5026 // pass both of them.
5027 newEvent->mButton = aMouseEvent->mButton;
5028 newEvent->mButtons = aMouseEvent->mButtons;
5029 newEvent->mPressure = aMouseEvent->mPressure;
5030 }
5031
5032 newEvent->mInputSource = aMouseEvent->mInputSource;
5033 newEvent->pointerId = aMouseEvent->pointerId;
5034
5035 return newEvent;
5036}
5037
5038already_AddRefed<nsIWidget>
5039EventStateManager::DispatchMouseOrPointerBoundaryEvent(
5040 WidgetMouseEvent* aMouseEvent, EventMessage aMessage,
5041 nsIContent* aTargetContent, nsIContent* aRelatedContent) {
5042 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"
, 5045); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5045; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
65
Taking false branch
5043 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"
, 5045); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5045; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5044 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"
, 5045); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5045; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5045 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"
, 5045); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5045; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5046
5047 // https://w3c.github.io/pointerlock/#dom-element-requestpointerlock
5048 // "[Once in the locked state...E]vents that require the concept
5049 // of a mouse cursor must not be dispatched (for example: mouseover,
5050 // mouseout...).
5051 // XXXedgar should we also block pointer events?
5052 if (PointerLockManager::IsLocked() &&
66
Loop condition is false. Exiting loop
67
Assuming the condition is true
68
Taking true branch
5053 (aMessage
67.1
'aMessage' is not equal to eMouseLeave
== eMouseLeave || aMessage
67.2
'aMessage' is not equal to eMouseEnter
== eMouseEnter ||
5054 aMessage
67.3
'aMessage' is not equal to eMouseOver
== eMouseOver || aMessage
67.4
'aMessage' is equal to eMouseOut
== eMouseOut)) {
5055 mCurrentTargetContent = nullptr;
5056 nsCOMPtr<Element> pointerLockedElement =
5057 PointerLockManager::GetLockedElement();
5058 if (!pointerLockedElement) {
69
Taking false branch
5059 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"
, 5059)
;
5060 return nullptr;
5061 }
5062 nsIFrame* const pointerLockedFrame =
70
'pointerLockedFrame' initialized here
5063 mPresContext->GetPrimaryFrameFor(pointerLockedElement);
5064 if (NS_WARN_IF(!pointerLockedFrame)NS_warn_if_impl(!pointerLockedFrame, "!pointerLockedFrame", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5064)
) {
71
Assuming 'pointerLockedFrame' is null
72
Assuming the condition is false
73
Taking false branch
5065 return nullptr;
5066 }
5067 return do_AddRef(pointerLockedFrame->GetNearestWidget());
74
Called C++ object pointer is null
5068 }
5069
5070 mCurrentTargetContent = nullptr;
5071
5072 if (!aTargetContent) {
5073 return nullptr;
5074 }
5075
5076 // Store the widget before dispatching the event because some event listeners
5077 // of the dispatching event may cause reframe the target or remove the target
5078 // from the tree.
5079 nsCOMPtr<nsIWidget> targetWidget;
5080 if (nsIFrame* const targetFrame =
5081 mPresContext->GetPrimaryFrameFor(aTargetContent)) {
5082 targetWidget = targetFrame->GetNearestWidget();
5083 }
5084
5085 nsCOMPtr<nsIContent> targetContent = aTargetContent;
5086 nsCOMPtr<nsIContent> relatedContent = aRelatedContent;
5087
5088 UniquePtr<WidgetMouseEvent> dispatchEvent =
5089 CreateMouseOrPointerWidgetEvent(aMouseEvent, aMessage, relatedContent);
5090
5091 AutoWeakFrame previousTarget = mCurrentTarget;
5092 mCurrentTargetContent = targetContent;
5093
5094 nsEventStatus status = nsEventStatus_eIgnore;
5095 ESMEventCB callback(targetContent);
5096 RefPtr<nsPresContext> presContext = mPresContext;
5097 EventDispatcher::Dispatch(targetContent, presContext, dispatchEvent.get(),
5098 nullptr, &status, &callback);
5099
5100 if (mPresContext) {
5101 // If we are entering/leaving remote content, dispatch a mouse enter/exit
5102 // event to the remote frame.
5103 if (IsTopLevelRemoteTarget(targetContent)) {
5104 if (aMessage == eMouseOut) {
5105 // For remote content, send a puppet widget mouse exit event.
5106 UniquePtr<WidgetMouseEvent> remoteEvent =
5107 CreateMouseOrPointerWidgetEvent(aMouseEvent, eMouseExitFromWidget,
5108 relatedContent);
5109 remoteEvent->mExitFrom = Some(WidgetMouseEvent::ePuppet);
5110
5111 // mCurrentTarget is set to the new target, so we must reset it to the
5112 // old target and then dispatch a cross-process event. (mCurrentTarget
5113 // will be set back below.) HandleCrossProcessEvent will query for the
5114 // proper target via GetEventTarget which will return mCurrentTarget.
5115 mCurrentTarget = mPresContext->GetPrimaryFrameFor(targetContent);
5116 HandleCrossProcessEvent(remoteEvent.get(), &status);
5117 } else if (aMessage == eMouseOver) {
5118 UniquePtr<WidgetMouseEvent> remoteEvent =
5119 CreateMouseOrPointerWidgetEvent(aMouseEvent, eMouseEnterIntoWidget,
5120 relatedContent);
5121 HandleCrossProcessEvent(remoteEvent.get(), &status);
5122 }
5123 }
5124 }
5125
5126 mCurrentTargetContent = nullptr;
5127 mCurrentTarget = previousTarget;
5128
5129 return targetWidget.forget();
5130}
5131
5132static nsIContent* FindCommonAncestor(nsIContent* aNode1, nsIContent* aNode2) {
5133 if (!aNode1 || !aNode2) {
5134 return nullptr;
5135 }
5136 return nsContentUtils::GetCommonFlattenedTreeAncestor(aNode1, aNode2);
5137}
5138
5139class EnterLeaveDispatcher {
5140 public:
5141 EnterLeaveDispatcher(EventStateManager* aESM, nsIContent* aTarget,
5142 nsIContent* aRelatedTarget,
5143 WidgetMouseEvent* aMouseEvent,
5144 EventMessage aEventMessage)
5145 : mESM(aESM), mMouseEvent(aMouseEvent), mEventMessage(aEventMessage) {
5146 nsPIDOMWindowInner* win =
5147 aTarget ? aTarget->OwnerDoc()->GetInnerWindow() : nullptr;
5148 if (aMouseEvent->AsPointerEvent()
5149 ? win && win->HasPointerEnterLeaveEventListeners()
5150 : win && win->HasMouseEnterLeaveEventListeners()) {
5151 mRelatedTarget =
5152 aRelatedTarget ? aRelatedTarget->FindFirstNonChromeOnlyAccessContent()
5153 : nullptr;
5154 nsINode* commonParent = FindCommonAncestor(aTarget, aRelatedTarget);
5155 nsIContent* current = aTarget;
5156 // Note, it is ok if commonParent is null!
5157 while (current && current != commonParent) {
5158 if (!current->ChromeOnlyAccess()) {
5159 mTargets.AppendObject(current);
5160 }
5161 // mouseenter/leave is fired only on elements.
5162 current = current->GetFlattenedTreeParent();
5163 }
5164 }
5165 }
5166
5167 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
5168 MOZ_CAN_RUN_SCRIPT_BOUNDARY void Dispatch() {
5169 if (mEventMessage == eMouseEnter || mEventMessage == ePointerEnter) {
5170 for (int32_t i = mTargets.Count() - 1; i >= 0; --i) {
5171 nsCOMPtr<nsIWidget> widget = mESM->DispatchMouseOrPointerBoundaryEvent(
5172 mMouseEvent, mEventMessage, MOZ_KnownLive(mTargets[i])(mTargets[i]),
5173 mRelatedTarget);
5174 }
5175 } else {
5176 for (int32_t i = 0; i < mTargets.Count(); ++i) {
5177 nsCOMPtr<nsIWidget> widget = mESM->DispatchMouseOrPointerBoundaryEvent(
5178 mMouseEvent, mEventMessage, MOZ_KnownLive(mTargets[i])(mTargets[i]),
5179 mRelatedTarget);
5180 }
5181 }
5182 }
5183
5184 // Nothing overwrites anything after constructor. Please remove MOZ_KnownLive
5185 // and MOZ_KNOWN_LIVE if anything marked as such becomes mutable.
5186 const RefPtr<EventStateManager> mESM;
5187 nsCOMArray<nsIContent> mTargets;
5188 MOZ_KNOWN_LIVE nsCOMPtr<nsIContent> mRelatedTarget;
5189 WidgetMouseEvent* mMouseEvent;
5190 EventMessage mEventMessage;
5191};
5192
5193void EventStateManager::NotifyMouseOut(WidgetMouseEvent* aMouseEvent,
5194 nsIContent* aMovingInto) {
5195 const bool isPointer = aMouseEvent->mClass == ePointerEventClass;
25
Assuming field 'mClass' is not equal to ePointerEventClass
44
Assuming field 'mClass' is not equal to ePointerEventClass
5196 LogModule* const logModule =
5197 isPointer
25.1
'isPointer' is false
44.1
'isPointer' is false
? sPointerBoundaryLog : sMouseBoundaryLog;
26
'?' condition is false
45
'?' condition is false
5198
5199 RefPtr<OverOutElementsWrapper> wrapper = GetWrapperByEventID(aMouseEvent);
5200
5201 // If there is no deepest "leave" event target, that means the last "over"
5202 // target has already been removed from the tree. Therefore, checking only
5203 // the "leave" event target is enough.
5204 if (!wrapper || !wrapper->GetDeepestLeaveEventTarget()) {
27
Assuming the condition is false
28
Taking false branch
46
Assuming the condition is false
47
Taking false branch
5205 return;
5206 }
5207 // Before firing "out" and/or "leave" events, check for recursion
5208 if (wrapper->IsDispatchingOutEventOnLastOverEventTarget()) {
29
Taking false branch
48
Taking false branch
5209 return;
5210 }
5211
5212 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)
30
Assuming the condition is false
31
Taking true branch
32
'?' condition is false
33
Loop condition is false. Exiting loop
49
Assuming the condition is false
50
Taking true branch
51
'?' condition is false
52
Loop condition is false. Exiting loop
5213 ("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)
5214 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)
5215 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)
;
5216
5217 // XXX If a content node is a container of remove content, it should be
5218 // replaced with them and its children should not be visible. Therefore,
5219 // if the deepest "enter" target is not the last "over" target, i.e., the
5220 // last "over" target has been removed from the DOM tree, it means that the
5221 // child/descendant was not replaced by remote content. So,
5222 // wrapper->GetOutEventTaget() may be enough here.
5223 if (RefPtr<nsFrameLoaderOwner> flo =
34
Taking true branch
53
Taking false branch
5224 do_QueryObject(wrapper->GetDeepestLeaveEventTarget())) {
5225 if (BrowsingContext* bc = flo->GetExtantBrowsingContext()) {
35
Assuming 'bc' is non-null
36
Taking true branch
5226 if (nsIDocShell* docshell = bc->GetDocShell()) {
37
Assuming 'docshell' is non-null
38
Taking true branch
5227 if (RefPtr<nsPresContext> presContext = docshell->GetPresContext()) {
39
Taking true branch
5228 EventStateManager* kidESM = presContext->EventStateManager();
5229 // Not moving into any element in this subdocument
5230 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)
40
Assuming the condition is false
41
Taking true branch
42
Loop condition is false. Exiting loop
5231 ("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)
5232 "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)
5233 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)
;
5234 kidESM->NotifyMouseOut(aMouseEvent, nullptr);
43
Calling 'EventStateManager::NotifyMouseOut'
5235 }
5236 }
5237 }
5238 }
5239 // That could have caused DOM events which could wreak havoc. Reverify
5240 // things and be careful.
5241 if (!wrapper->GetDeepestLeaveEventTarget()) {
54
Taking false branch
5242 return;
5243 }
5244
5245 wrapper->WillDispatchOutAndOrLeaveEvent();
5246
5247 // Don't touch hover state if aMovingInto is non-null. Caller will update
5248 // hover state itself, and we have optimizations for hover switching between
5249 // two nearby elements both deep in the DOM tree that would be defeated by
5250 // switching the hover state to null here.
5251 if (!aMovingInto
54.1
'aMovingInto' is null
&& !isPointer
54.2
'isPointer' is false
) {
55
Taking true branch
5252 // Unset :hover
5253 SetContentState(nullptr, ElementState::HOVER);
5254 }
5255
5256 EnterLeaveDispatcher leaveDispatcher(
5257 this, wrapper->GetDeepestLeaveEventTarget(), aMovingInto, aMouseEvent,
5258 isPointer
55.1
'isPointer' is false
? ePointerLeave : eMouseLeave);
56
'?' condition is false
5259
5260 // "out" events hould be fired only when the deepest "leave" event target
5261 // is the last "over" event target.
5262 if (nsCOMPtr<nsIContent> outEventTarget = wrapper->GetOutEventTarget()) {
57
Taking true branch
5263 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)
58
Assuming the condition is false
59
Taking true branch
60
'?' condition is false
61
'?' condition is true
62
Loop condition is false. Exiting loop
5264 ("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)
5265 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)
5266 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)
5267 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)
;
5268 nsCOMPtr<nsIWidget> widget = DispatchMouseOrPointerBoundaryEvent(
64
Calling 'EventStateManager::DispatchMouseOrPointerBoundaryEvent'
5269 aMouseEvent, isPointer
62.1
'isPointer' is false
? ePointerOut : eMouseOut, outEventTarget,
63
'?' condition is false
5270 aMovingInto);
5271 }
5272
5273 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)
5274 ("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)
5275 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)
5276 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)
5277 ? 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)
5278 : "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)
5279 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)
;
5280 leaveDispatcher.Dispatch();
5281
5282 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)
5283 ("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)
;
5284 wrapper->DidDispatchOutAndOrLeaveEvent();
5285}
5286
5287void EventStateManager::RecomputeMouseEnterStateForRemoteFrame(
5288 Element& aElement) {
5289 if (!mMouseEnterLeaveHelper ||
5290 mMouseEnterLeaveHelper->GetDeepestLeaveEventTarget() != &aElement) {
5291 return;
5292 }
5293
5294 if (BrowserParent* remote = BrowserParent::GetFrom(&aElement)) {
5295 remote->MouseEnterIntoWidget();
5296 }
5297}
5298
5299void EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
5300 nsIContent* aContent) {
5301 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"
, 5301); MOZ_PretendNoReturn(); } } while (0)
;
5302
5303 const bool isPointer = aMouseEvent->mClass == ePointerEventClass;
5304 LogModule* const logModule =
5305 isPointer ? sPointerBoundaryLog : sMouseBoundaryLog;
5306
5307 RefPtr<OverOutElementsWrapper> wrapper = GetWrapperByEventID(aMouseEvent);
5308
5309 // If we have next "out" event target and it's the new "over" target, we don't
5310 // need to dispatch "out" nor "enter" event.
5311 if (!wrapper || aContent == wrapper->GetOutEventTarget()) {
5312 return;
5313 }
5314
5315 // Before firing "over" and "enter" events, check for recursion
5316 if (wrapper->IsDispatchingOverEventOn(aContent)) {
5317 return;
5318 }
5319
5320 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)
5321 ("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)
5322 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)
5323 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)
;
5324
5325 // Check to see if we're a subdocument and if so update the parent
5326 // document's ESM state to indicate that the mouse is over the
5327 // content associated with our subdocument.
5328 EnsureDocument(mPresContext);
5329 if (Document* parentDoc = mDocument->GetInProcessParentDocument()) {
5330 if (nsCOMPtr<nsIContent> docContent = mDocument->GetEmbedderElement()) {
5331 if (PresShell* parentPresShell = parentDoc->GetPresShell()) {
5332 RefPtr<EventStateManager> parentESM =
5333 parentPresShell->GetPresContext()->EventStateManager();
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, "Notifying parent EventStateManager (%p) of \"over\" "
"event...", parentESM.get()); } } while (0)
5335 ("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)
5336 "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)
5337 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)
;
5338 parentESM->NotifyMouseOver(aMouseEvent, docContent);
5339 }
5340 }
5341 }
5342 // Firing the DOM event in the parent document could cause all kinds
5343 // of havoc. Reverify and take care.
5344 if (aContent == wrapper->GetOutEventTarget()) {
5345 return;
5346 }
5347
5348 // Remember the deepest leave event target as the related content for the
5349 // DispatchMouseOrPointerBoundaryEvent() call below, since NotifyMouseOut()
5350 // resets it, bug 298477.
5351 nsCOMPtr<nsIContent> deepestLeaveEventTarget =
5352 wrapper->GetDeepestLeaveEventTarget();
5353
5354 EnterLeaveDispatcher enterDispatcher(this, aContent, deepestLeaveEventTarget,
5355 aMouseEvent,
5356 isPointer ? ePointerEnter : eMouseEnter);
5357
5358 if (!isPointer) {
5359 SetContentState(aContent, ElementState::HOVER);
5360 }
5361
5362 NotifyMouseOut(aMouseEvent, aContent);
5363
5364 wrapper->WillDispatchOverAndEnterEvent(aContent);
5365
5366 // Fire mouseover
5367 // XXX If aContent has already been removed from the DOM tree, what should we
5368 // do? At least, dispatching `mouseover` on it is odd.
5369 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)
5370 ("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)
5371 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)
5372 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)
;
5373 nsCOMPtr<nsIWidget> targetWidget = DispatchMouseOrPointerBoundaryEvent(
5374 aMouseEvent, isPointer ? ePointerOver : eMouseOver, aContent,
5375 deepestLeaveEventTarget);
5376
5377 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)
5378 ("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)
5379 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)
5380 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)
;
5381 enterDispatcher.Dispatch();
5382
5383 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)
5384 ("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)
5385 "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)
5386 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)
;
5387 wrapper->DidDispatchOverAndEnterEvent(
5388 aContent->GetComposedDoc() == mDocument ? aContent : nullptr,
5389 targetWidget);
5390}
5391
5392// Returns the center point of the window's client area. This is
5393// in widget coordinates, i.e. relative to the widget's top-left
5394// corner, not in screen coordinates, the same units that UIEvent::
5395// refpoint is in. It may not be the exact center of the window if
5396// the platform requires rounding the coordinate.
5397static LayoutDeviceIntPoint GetWindowClientRectCenter(nsIWidget* aWidget) {
5398 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"
, 5398); return LayoutDeviceIntPoint(0, 0); } } while (false)
;
5399
5400 LayoutDeviceIntRect rect = aWidget->GetClientBounds();
5401 LayoutDeviceIntPoint point(rect.width / 2, rect.height / 2);
5402 int32_t round = aWidget->RoundsWidgetCoordinatesTo();
5403 point.x = point.x / round * round;
5404 point.y = point.y / round * round;
5405 return point;
5406}
5407
5408void EventStateManager::GeneratePointerEnterExit(EventMessage aMessage,
5409 WidgetMouseEvent* aEvent) {
5410 WidgetPointerEvent pointerEvent(*aEvent);
5411 pointerEvent.mMessage = aMessage;
5412 GenerateMouseEnterExit(&pointerEvent);
5413}
5414
5415/* static */
5416void EventStateManager::UpdateLastRefPointOfMouseEvent(
5417 WidgetMouseEvent* aMouseEvent) {
5418 if (aMouseEvent->mMessage != eMouseMove &&
5419 aMouseEvent->mMessage != ePointerMove) {
5420 return;
5421 }
5422
5423 // Mouse movement is reported on the MouseEvent.movement{X,Y} fields.
5424 // Movement is calculated in UIEvent::GetMovementPoint() as:
5425 // previous_mousemove_mRefPoint - current_mousemove_mRefPoint.
5426 if (PointerLockManager::IsLocked() && aMouseEvent->mWidget) {
5427 // The pointer is locked. If the pointer is not located at the center of
5428 // the window, dispatch a synthetic mousemove to return the pointer there.
5429 // Doing this between "real" pointer moves gives the impression that the
5430 // (locked) pointer can continue moving and won't stop at the screen
5431 // boundary. We cancel the synthetic event so that we don't end up
5432 // dispatching the centering move event to content.
5433 aMouseEvent->mLastRefPoint =
5434 GetWindowClientRectCenter(aMouseEvent->mWidget);
5435
5436 } else if (sLastRefPoint == kInvalidRefPoint) {
5437 // We don't have a valid previous mousemove mRefPoint. This is either
5438 // the first move we've encountered, or the mouse has just re-entered
5439 // the application window. We should report (0,0) movement for this
5440 // case, so make the current and previous mRefPoints the same.
5441 aMouseEvent->mLastRefPoint = aMouseEvent->mRefPoint;
5442 } else {
5443 aMouseEvent->mLastRefPoint = sLastRefPoint;
5444 }
5445}
5446
5447/* static */
5448void EventStateManager::ResetPointerToWindowCenterWhilePointerLocked(
5449 WidgetMouseEvent* aMouseEvent) {
5450 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"
, 5450); AnnotateMozCrashReason("MOZ_ASSERT" "(" "PointerLockManager::IsLocked()"
")"); do { *((volatile int*)__null) = 5450; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5451 if ((aMouseEvent->mMessage != eMouseMove &&
5452 aMouseEvent->mMessage != ePointerMove) ||
5453 !aMouseEvent->mWidget) {
5454 return;
5455 }
5456
5457 // We generate pointermove from mousemove event, so only synthesize native
5458 // mouse move and update sSynthCenteringPoint by mousemove event.
5459 bool updateSynthCenteringPoint = aMouseEvent->mMessage == eMouseMove;
5460
5461 // The pointer is locked. If the pointer is not located at the center of
5462 // the window, dispatch a synthetic mousemove to return the pointer there.
5463 // Doing this between "real" pointer moves gives the impression that the
5464 // (locked) pointer can continue moving and won't stop at the screen
5465 // boundary. We cancel the synthetic event so that we don't end up
5466 // dispatching the centering move event to content.
5467 LayoutDeviceIntPoint center = GetWindowClientRectCenter(aMouseEvent->mWidget);
5468
5469 if (aMouseEvent->mRefPoint != center && updateSynthCenteringPoint) {
5470 // Mouse move doesn't finish at the center of the window. Dispatch a
5471 // synthetic native mouse event to move the pointer back to the center
5472 // of the window, to faciliate more movement. But first, record that
5473 // we've dispatched a synthetic mouse movement, so we can cancel it
5474 // in the other branch here.
5475 sSynthCenteringPoint = center;
5476 // XXX Once we fix XXX comments in SetPointerLock about this API, we could
5477 // restrict that this API works only in the automation mode or in the
5478 // pointer locked situation.
5479 aMouseEvent->mWidget->SynthesizeNativeMouseMove(
5480 center + aMouseEvent->mWidget->WidgetToScreenOffset(), nullptr);
5481 } else if (aMouseEvent->mRefPoint == sSynthCenteringPoint) {
5482 // This is the "synthetic native" event we dispatched to re-center the
5483 // pointer. Cancel it so we don't expose the centering move to content.
5484 aMouseEvent->StopPropagation();
5485 // Clear sSynthCenteringPoint so we don't cancel other events
5486 // targeted at the center.
5487 if (updateSynthCenteringPoint) {
5488 sSynthCenteringPoint = kInvalidRefPoint;
5489 }
5490 }
5491}
5492
5493/* static */
5494void EventStateManager::UpdateLastPointerPosition(
5495 WidgetMouseEvent* aMouseEvent) {
5496 if (aMouseEvent->mMessage != eMouseMove) {
5497 return;
5498 }
5499 sLastRefPoint = aMouseEvent->mRefPoint;
5500}
5501
5502void EventStateManager::GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent) {
5503 EnsureDocument(mPresContext);
5504 if (!mDocument) return;
16
Taking false branch
5505
5506 // Hold onto old target content through the event and reset after.
5507 nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
5508
5509 switch (aMouseEvent->mMessage) {
17
Control jumps to 'case ePointerUp:' at line 5527
5510 case eMouseMove:
5511 case ePointerMove:
5512 case ePointerDown:
5513 case ePointerGotCapture: {
5514 // Get the target content target (mousemove target == mouseover target)
5515 nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
5516 if (!targetElement) {
5517 // We're always over the document root, even if we're only
5518 // over dead space in a page (whose frame is not associated with
5519 // any content) or in print preview dead space
5520 targetElement = mDocument->GetRootElement();
5521 }
5522 if (targetElement) {
5523 NotifyMouseOver(aMouseEvent, targetElement);
5524 }
5525 break;
5526 }
5527 case ePointerUp: {
5528 if (!StaticPrefs::
18
Assuming the condition is false
19
Taking false branch
5529 dom_events_mouse_pointer_boundary_keep_enter_targets_after_over_target_removed()) {
5530 // In the legacy mode, we should do nothing if the event has not been
5531 // dispatched yet (i.e., called by PreHandleEvent).
5532 // On the other hand, if the event was dispatched (i.e., called by
5533 // PostEventHandler), we need to dispatch "pointerout" and
5534 // "pointerleave" events because the pointer will be removed
5535 // (invalidated) by the "pointerup" operation.
5536 if (!aMouseEvent->mFlags.mDispatchedAtLeastOnce) {
5537 break;
5538 }
5539 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"
, 5539); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aMouseEvent->InputSourceSupportsHover()"
")"); do { *((volatile int*)__null) = 5539; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5540 // Get the target content target (pointermove target == pointerover
5541 // target)
5542 nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
5543 if (!targetElement) {
5544 // We're always over the document root, even if we're only
5545 // over dead space in a page (whose frame is not associated with
5546 // any content) or in print preview dead space
5547 targetElement = mDocument->GetRootElement();
5548 }
5549 if (targetElement) {
5550 // XXX It's odd to override the `pointerout` event target with the
5551 // content under the pointer or something because it may have never
5552 // received `pointerover` event. I think that this was required for
5553 // digitizer which supports hover state (bug 985511). However, this
5554 // is now not called at ePointerUp if the device supports hover.
5555 RefPtr<OverOutElementsWrapper> helper =
5556 GetWrapperByEventID(aMouseEvent);
5557 if (helper) {
5558 helper->OverrideOverEventTarget(targetElement);
5559 }
5560 NotifyMouseOut(aMouseEvent, nullptr);
5561 }
5562 break;
5563 }
5564
5565 if (aMouseEvent->mFlags.mDispatchedAtLeastOnce) {
20
Assuming field 'mDispatchedAtLeastOnce' is true
21
Taking true branch
5566 // If we've already dispatched the pointerup event caused by
5567 // non-hoverable input device like touch, we need to synthesize
5568 // pointerout and pointerleave events because the poiner is valid only
5569 // while it's "down".
5570 if (!aMouseEvent->InputSourceSupportsHover()) {
22
Assuming the condition is true
23
Taking true branch
5571 NotifyMouseOut(aMouseEvent, nullptr);
24
Calling 'EventStateManager::NotifyMouseOut'
5572 }
5573 break;
5574 }
5575
5576 // If we're going to dispatch the pointerup event and the element under
5577 // the pointer is changed from the previous pointer event dispatching, we
5578 // need to dispatch pointer boundary events. If the pointing device is
5579 // hoverable, we always need to do it. Otherwise, an element captures the
5580 // pointer by default. If so, we don't need the boundary events, but if
5581 // the capture has already been released, e.g., by the capturing element
5582 // is removed, we need to dispatch the pointer boundary event the same
5583 // way as with hoverable pointer.
5584 if (aMouseEvent->InputSourceSupportsHover() ||
5585 !PointerEventHandler::GetPointerCapturingElement(
5586 aMouseEvent->pointerId)) {
5587 nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
5588 if (!targetElement) {
5589 targetElement = mDocument->GetRootElement();
5590 }
5591 if (targetElement) {
5592 NotifyMouseOver(aMouseEvent, targetElement);
5593 }
5594 break;
5595 }
5596 break;
5597 }
5598 case ePointerLeave:
5599 case ePointerCancel:
5600 case eMouseExitFromWidget: {
5601 // This is actually the window mouse exit or pointer leave event. We're
5602 // not moving into any new element.
5603
5604 RefPtr<OverOutElementsWrapper> helper = GetWrapperByEventID(aMouseEvent);
5605 if (helper) {
5606 nsCOMPtr<nsIWidget> lastOverWidget = helper->GetLastOverWidget();
5607 if (lastOverWidget &&
5608 nsContentUtils::GetTopLevelWidget(aMouseEvent->mWidget) !=
5609 nsContentUtils::GetTopLevelWidget(lastOverWidget)) {
5610 // the Mouse/PointerOut event widget doesn't have same top widget with
5611 // the last over event target, it's a spurious event for the frame for
5612 // the target.
5613 break;
5614 }
5615 }
5616
5617 // Reset sLastRefPoint, so that we'll know not to report any
5618 // movement the next time we re-enter the window.
5619 sLastRefPoint = kInvalidRefPoint;
5620
5621 NotifyMouseOut(aMouseEvent, nullptr);
5622 break;
5623 }
5624 default:
5625 break;
5626 }
5627
5628 // reset mCurretTargetContent to what it was
5629 mCurrentTargetContent = targetBeforeEvent;
5630}
5631
5632OverOutElementsWrapper* EventStateManager::GetWrapperByEventID(
5633 WidgetMouseEvent* aEvent) {
5634 WidgetPointerEvent* pointer = aEvent->AsPointerEvent();
5635 if (!pointer) {
5636 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"
, 5636); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->AsMouseEvent() != nullptr"
")"); do { *((volatile int*)__null) = 5636; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5637 if (!mMouseEnterLeaveHelper) {
5638 mMouseEnterLeaveHelper = new OverOutElementsWrapper(
5639 OverOutElementsWrapper::BoundaryEventType::Mouse);
5640 }
5641 return mMouseEnterLeaveHelper;
5642 }
5643 return mPointersEnterLeaveHelper.GetOrInsertNew(
5644 pointer->pointerId, OverOutElementsWrapper::BoundaryEventType::Pointer);
5645}
5646
5647/* static */
5648void EventStateManager::SetPointerLock(nsIWidget* aWidget,
5649 nsPresContext* aPresContext) {
5650 // Reset mouse wheel transaction
5651 WheelTransaction::EndTransaction();
5652
5653 // Deal with DnD events
5654 nsCOMPtr<nsIDragService> dragService =
5655 do_GetService("@mozilla.org/widget/dragservice;1");
5656
5657 if (PointerLockManager::IsLocked()) {
5658 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"
, 5658); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWidget" ") ("
"Locking pointer requires a widget" ")"); do { *((volatile int
*)__null) = 5658; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
5659 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"
, 5659); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresContext"
") (" "Locking pointer requires a presContext" ")"); do { *(
(volatile int*)__null) = 5659; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
5660
5661 // Release all pointer capture when a pointer lock is successfully applied
5662 // on an element.
5663 PointerEventHandler::ReleaseAllPointerCapture();
5664
5665 // Store the last known ref point so we can reposition the pointer after
5666 // unlock.
5667 sPreLockScreenPoint = LayoutDeviceIntPoint::Round(
5668 sLastScreenPoint * aPresContext->CSSToDevPixelScale());
5669
5670 // Fire a synthetic mouse move to ensure event state is updated. We first
5671 // set the mouse to the center of the window, so that the mouse event
5672 // doesn't report any movement.
5673 // XXX Cannot we do synthesize the native mousemove in the parent process
5674 // with calling LockNativePointer below? Then, we could make this API
5675 // work only in the automation mode.
5676 sLastRefPoint = GetWindowClientRectCenter(aWidget);
5677 aWidget->SynthesizeNativeMouseMove(
5678 sLastRefPoint + aWidget->WidgetToScreenOffset(), nullptr);
5679
5680 // Suppress DnD
5681 if (dragService) {
5682 dragService->Suppress();
5683 }
5684
5685 // Activate native pointer lock on platforms where it is required (Wayland)
5686 aWidget->LockNativePointer();
5687 } else {
5688 if (aWidget) {
5689 // Deactivate native pointer lock on platforms where it is required
5690 aWidget->UnlockNativePointer();
5691 }
5692
5693 // Reset SynthCenteringPoint to invalid so that next time we start
5694 // locking pointer, it has its initial value.
5695 sSynthCenteringPoint = kInvalidRefPoint;
5696 if (aWidget) {
5697 // Unlocking, so return pointer to the original position by firing a
5698 // synthetic mouse event. We first reset sLastRefPoint to its
5699 // pre-pointerlock position, so that the synthetic mouse event reports
5700 // no movement.
5701 sLastRefPoint = sPreLockScreenPoint - aWidget->WidgetToScreenOffset();
5702 // XXX Cannot we do synthesize the native mousemove in the parent process
5703 // with calling `UnlockNativePointer` above? Then, we could make this
5704 // API work only in the automation mode.
5705 aWidget->SynthesizeNativeMouseMove(sPreLockScreenPoint, nullptr);
5706 }
5707
5708 // Unsuppress DnD
5709 if (dragService) {
5710 dragService->Unsuppress();
5711 }
5712 }
5713}
5714
5715void EventStateManager::GenerateDragDropEnterExit(nsPresContext* aPresContext,
5716 WidgetDragEvent* aDragEvent) {
5717 // Hold onto old target content through the event and reset after.
5718 nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
5719
5720 switch (aDragEvent->mMessage) {
5721 case eDragOver: {
5722 // when dragging from one frame to another, events are fired in the
5723 // order: dragexit, dragenter, dragleave
5724 if (sLastDragOverFrame != mCurrentTarget) {
5725 // We'll need the content, too, to check if it changed separately from
5726 // the frames.
5727 nsCOMPtr<nsIContent> lastContent;
5728 nsCOMPtr<nsIContent> targetContent;
5729 mCurrentTarget->GetContentForEvent(aDragEvent,
5730 getter_AddRefs(targetContent));
5731 if (targetContent && targetContent->IsText()) {
5732 targetContent = targetContent->GetFlattenedTreeParent();
5733 }
5734
5735 if (sLastDragOverFrame) {
5736 // The frame has changed but the content may not have. Check before
5737 // dispatching to content
5738 sLastDragOverFrame->GetContentForEvent(aDragEvent,
5739 getter_AddRefs(lastContent));
5740 if (lastContent && lastContent->IsText()) {
5741 lastContent = lastContent->GetFlattenedTreeParent();
5742 }
5743
5744 RefPtr<nsPresContext> presContext = sLastDragOverFrame->PresContext();
5745 FireDragEnterOrExit(presContext, aDragEvent, eDragExit, targetContent,
5746 lastContent, sLastDragOverFrame);
5747 nsIContent* target = sLastDragOverFrame
5748 ? sLastDragOverFrame.GetFrame()->GetContent()
5749 : nullptr;
5750 // XXXedgar, look like we need to consider fission OOP iframe, too.
5751 if (IsTopLevelRemoteTarget(target)) {
5752 // Dragging something and moving from web content to chrome only
5753 // fires dragexit and dragleave to xul:browser. We have to forward
5754 // dragexit to sLastDragOverFrame when its content is a remote
5755 // target. We don't forward dragleave since it's generated from
5756 // dragexit.
5757 WidgetDragEvent remoteEvent(aDragEvent->IsTrusted(), eDragExit,
5758 aDragEvent->mWidget);
5759 remoteEvent.AssignDragEventData(*aDragEvent, true);
5760 remoteEvent.mFlags.mIsSynthesizedForTests =
5761 aDragEvent->mFlags.mIsSynthesizedForTests;
5762 nsEventStatus remoteStatus = nsEventStatus_eIgnore;
5763 HandleCrossProcessEvent(&remoteEvent, &remoteStatus);
5764 }
5765 }
5766
5767 AutoWeakFrame currentTraget = mCurrentTarget;
5768 FireDragEnterOrExit(aPresContext, aDragEvent, eDragEnter, lastContent,
5769 targetContent, currentTraget);
5770
5771 if (sLastDragOverFrame) {
5772 RefPtr<nsPresContext> presContext = sLastDragOverFrame->PresContext();
5773 FireDragEnterOrExit(presContext, aDragEvent, eDragLeave,
5774 targetContent, lastContent, sLastDragOverFrame);
5775 }
5776
5777 sLastDragOverFrame = mCurrentTarget;
5778 }
5779 } break;
5780
5781 case eDragExit: {
5782 // This is actually the window mouse exit event.
5783 if (sLastDragOverFrame) {
5784 nsCOMPtr<nsIContent> lastContent;
5785 sLastDragOverFrame->GetContentForEvent(aDragEvent,
5786 getter_AddRefs(lastContent));
5787
5788 RefPtr<nsPresContext> lastDragOverFramePresContext =
5789 sLastDragOverFrame->PresContext();
5790 FireDragEnterOrExit(lastDragOverFramePresContext, aDragEvent, eDragExit,
5791 nullptr, lastContent, sLastDragOverFrame);
5792 FireDragEnterOrExit(lastDragOverFramePresContext, aDragEvent,
5793 eDragLeave, nullptr, lastContent,
5794 sLastDragOverFrame);
5795
5796 sLastDragOverFrame = nullptr;
5797 }
5798 } break;
5799
5800 default:
5801 break;
5802 }
5803
5804 // reset mCurretTargetContent to what it was
5805 mCurrentTargetContent = targetBeforeEvent;
5806
5807 // Now flush all pending notifications, for better responsiveness.
5808 FlushLayout(aPresContext);
5809}
5810
5811void EventStateManager::FireDragEnterOrExit(nsPresContext* aPresContext,
5812 WidgetDragEvent* aDragEvent,
5813 EventMessage aMessage,
5814 nsIContent* aRelatedTarget,
5815 nsIContent* aTargetContent,
5816 AutoWeakFrame& aTargetFrame) {
5817 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"
, 5818); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eDragLeave || aMessage == eDragExit || aMessage == eDragEnter"
")"); do { *((volatile int*)__null) = 5818; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5818 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"
, 5818); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eDragLeave || aMessage == eDragExit || aMessage == eDragEnter"
")"); do { *((volatile int*)__null) = 5818; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5819 nsEventStatus status = nsEventStatus_eIgnore;
5820 WidgetDragEvent event(aDragEvent->IsTrusted(), aMessage, aDragEvent->mWidget);
5821 event.AssignDragEventData(*aDragEvent, false);
5822 event.mFlags.mIsSynthesizedForTests =
5823 aDragEvent->mFlags.mIsSynthesizedForTests;
5824 event.mRelatedTarget = aRelatedTarget;
5825 if (aMessage == eDragExit && !StaticPrefs::dom_event_dragexit_enabled()) {
5826 event.mFlags.mOnlyChromeDispatch = true;
5827 }
5828
5829 mCurrentTargetContent = aTargetContent;
5830
5831 if (aTargetContent != aRelatedTarget) {
5832 // XXX This event should still go somewhere!!
5833 if (aTargetContent) {
5834 EventDispatcher::Dispatch(aTargetContent, aPresContext, &event, nullptr,
5835 &status);
5836 }
5837
5838 // adjust the drag hover if the dragenter event was cancelled or this is a
5839 // drag exit
5840 if (status == nsEventStatus_eConsumeNoDefault || aMessage == eDragExit) {
5841 SetContentState((aMessage == eDragEnter) ? aTargetContent : nullptr,
5842 ElementState::DRAGOVER);
5843 }
5844
5845 // collect any changes to moz cursor settings stored in the event's
5846 // data transfer.
5847 UpdateDragDataTransfer(&event);
5848 }
5849
5850 // Finally dispatch the event to the frame
5851 if (aTargetFrame) {
5852 aTargetFrame->HandleEvent(aPresContext, &event, &status);
5853 }
5854}
5855
5856void EventStateManager::UpdateDragDataTransfer(WidgetDragEvent* dragEvent) {
5857 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"
, 5857); MOZ_PretendNoReturn(); } } while (0)
;
5858 if (!dragEvent->mDataTransfer) {
5859 return;
5860 }
5861
5862 nsCOMPtr<nsIDragSession> dragSession =
5863 nsContentUtils::GetDragSession(mPresContext);
5864
5865 if (dragSession) {
5866 // the initial dataTransfer is the one from the dragstart event that
5867 // was set on the dragSession when the drag began.
5868 RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer();
5869 if (initialDataTransfer) {
5870 // retrieve the current moz cursor setting and save it.
5871 nsAutoString mozCursor;
5872 dragEvent->mDataTransfer->GetMozCursor(mozCursor);
5873 initialDataTransfer->SetMozCursor(mozCursor);
5874 }
5875 }
5876}
5877
5878nsresult EventStateManager::SetClickCount(WidgetMouseEvent* aEvent,
5879 nsEventStatus* aStatus,
5880 nsIContent* aOverrideClickTarget) {
5881 nsCOMPtr<nsIContent> mouseContent = aOverrideClickTarget;
5882 if (!mouseContent && mCurrentTarget) {
5883 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(mouseContent));
5884 }
5885 if (mouseContent && mouseContent->IsText()) {
5886 nsINode* parent = mouseContent->GetFlattenedTreeParentNode();
5887 if (parent && parent->IsContent()) {
5888 mouseContent = parent->AsContent();
5889 }
5890 }
5891
5892 LastMouseDownInfo& mouseDownInfo = GetLastMouseDownInfo(aEvent->mButton);
5893 if (aEvent->mMessage == eMouseDown) {
5894 mouseDownInfo.mLastMouseDownContent =
5895 !aEvent->mClickEventPrevented ? mouseContent : nullptr;
5896
5897 if (mouseDownInfo.mLastMouseDownContent) {
5898 if (HTMLInputElement* input = HTMLInputElement::FromNodeOrNull(
5899 mouseDownInfo.mLastMouseDownContent)) {
5900 mouseDownInfo.mLastMouseDownInputControlType =
5901 Some(input->ControlType());
5902 } else if (mouseDownInfo.mLastMouseDownContent
5903 ->IsInNativeAnonymousSubtree()) {
5904 if (HTMLInputElement* input = HTMLInputElement::FromNodeOrNull(
5905 mouseDownInfo.mLastMouseDownContent
5906 ->GetFlattenedTreeParent())) {
5907 mouseDownInfo.mLastMouseDownInputControlType =
5908 Some(input->ControlType());
5909 }
5910 }
5911 }
5912 } else {
5913 aEvent->mClickTarget =
5914 !aEvent->mClickEventPrevented
5915 ? GetCommonAncestorForMouseUp(
5916 mouseContent, mouseDownInfo.mLastMouseDownContent,
5917 mouseDownInfo.mLastMouseDownInputControlType)
5918 : nullptr;
5919 if (aEvent->mClickTarget) {
5920 aEvent->mClickCount = mouseDownInfo.mClickCount;
5921 mouseDownInfo.mClickCount = 0;
5922 } else {
5923 aEvent->mClickCount = 0;
5924 }
5925 mouseDownInfo.mLastMouseDownContent = nullptr;
5926 mouseDownInfo.mLastMouseDownInputControlType = Nothing();
5927 }
5928
5929 return NS_OK;
5930}
5931
5932// static
5933bool EventStateManager::EventCausesClickEvents(
5934 const WidgetMouseEvent& aMouseEvent) {
5935 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"
, 5935)
) {
5936 return false;
5937 }
5938 // If the mouseup event is synthesized event, we don't need to dispatch
5939 // click events.
5940 if (!aMouseEvent.IsReal()) {
5941 return false;
5942 }
5943 // If mouse is still over same element, clickcount will be > 1.
5944 // If it has moved it will be zero, so no click.
5945 if (!aMouseEvent.mClickCount || !aMouseEvent.mClickTarget) {
5946 return false;
5947 }
5948 // If click event was explicitly prevented, we shouldn't dispatch it.
5949 if (aMouseEvent.mClickEventPrevented) {
5950 return false;
5951 }
5952 // Check that the window isn't disabled before firing a click
5953 // (see bug 366544).
5954 return !(aMouseEvent.mWidget && !aMouseEvent.mWidget->IsEnabled());
5955}
5956
5957nsresult EventStateManager::InitAndDispatchClickEvent(
5958 WidgetMouseEvent* aMouseUpEvent, nsEventStatus* aStatus,
5959 EventMessage aMessage, PresShell* aPresShell, nsIContent* aMouseUpContent,
5960 AutoWeakFrame aCurrentTarget, bool aNoContentDispatch,
5961 nsIContent* aOverrideClickTarget) {
5962 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"
, 5962); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpEvent"
")"); do { *((volatile int*)__null) = 5962; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5963 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"
, 5963); AnnotateMozCrashReason("MOZ_ASSERT" "(" "EventCausesClickEvents(*aMouseUpEvent)"
")"); do { *((volatile int*)__null) = 5963; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5964 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"
, 5964); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpContent || aCurrentTarget || aOverrideClickTarget"
")"); do { *((volatile int*)__null) = 5964; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5965
5966 Maybe<WidgetPointerEvent> pointerEvent;
5967 Maybe<WidgetMouseEvent> mouseEvent;
5968 if (IsPointerEventMessage(aMessage)) {
5969 pointerEvent.emplace(aMouseUpEvent->IsTrusted(), aMessage,
5970 aMouseUpEvent->mWidget);
5971 } else {
5972 mouseEvent.emplace(aMouseUpEvent->IsTrusted(), aMessage,
5973 aMouseUpEvent->mWidget, WidgetMouseEvent::eReal);
5974 }
5975
5976 WidgetMouseEvent& mouseOrPointerEvent =
5977 pointerEvent.isSome() ? pointerEvent.ref() : mouseEvent.ref();
5978
5979 mouseOrPointerEvent.mRefPoint = aMouseUpEvent->mRefPoint;
5980 mouseOrPointerEvent.mClickCount = aMouseUpEvent->mClickCount;
5981 mouseOrPointerEvent.mModifiers = aMouseUpEvent->mModifiers;
5982 mouseOrPointerEvent.mButtons = aMouseUpEvent->mButtons;
5983 mouseOrPointerEvent.mTimeStamp = aMouseUpEvent->mTimeStamp;
5984 mouseOrPointerEvent.mFlags.mOnlyChromeDispatch = aNoContentDispatch;
5985 mouseOrPointerEvent.mFlags.mNoContentDispatch = aNoContentDispatch;
5986 mouseOrPointerEvent.mButton = aMouseUpEvent->mButton;
5987 mouseOrPointerEvent.pointerId = aMouseUpEvent->pointerId;
5988 mouseOrPointerEvent.mInputSource = aMouseUpEvent->mInputSource;
5989 nsIContent* target = aMouseUpContent;
5990 nsIFrame* targetFrame = aCurrentTarget;
5991 if (aOverrideClickTarget) {
5992 target = aOverrideClickTarget;
5993 targetFrame = aOverrideClickTarget->GetPrimaryFrame();
5994 }
5995
5996 if (!target->IsInComposedDoc()) {
5997 return NS_OK;
5998 }
5999
6000 // Use local event status for each click event dispatching since it'll be
6001 // cleared by EventStateManager::PreHandleEvent(). Therefore, dispatching
6002 // an event means that previous event status will be ignored.
6003 nsEventStatus status = nsEventStatus_eIgnore;
6004 nsresult rv = aPresShell->HandleEventWithTarget(
6005 &mouseOrPointerEvent, targetFrame, MOZ_KnownLive(target)(target), &status);
6006
6007 // Copy mMultipleActionsPrevented flag from a click event to the mouseup
6008 // event only when it's set to true. It may be set to true if an editor has
6009 // already handled it. This is important to avoid two or more default
6010 // actions handled here.
6011 aMouseUpEvent->mFlags.mMultipleActionsPrevented |=
6012 mouseOrPointerEvent.mFlags.mMultipleActionsPrevented;
6013 // If current status is nsEventStatus_eConsumeNoDefault, we don't need to
6014 // overwrite it.
6015 if (*aStatus == nsEventStatus_eConsumeNoDefault) {
6016 return rv;
6017 }
6018 // If new status is nsEventStatus_eConsumeNoDefault or
6019 // nsEventStatus_eConsumeDoDefault, use it.
6020 if (status == nsEventStatus_eConsumeNoDefault ||
6021 status == nsEventStatus_eConsumeDoDefault) {
6022 *aStatus = status;
6023 return rv;
6024 }
6025 // Otherwise, keep the original status.
6026 return rv;
6027}
6028
6029nsresult EventStateManager::PostHandleMouseUp(
6030 WidgetMouseEvent* aMouseUpEvent, nsEventStatus* aStatus,
6031 nsIContent* aOverrideClickTarget) {
6032 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"
, 6032); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpEvent"
")"); do { *((volatile int*)__null) = 6032; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6033 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"
, 6033); AnnotateMozCrashReason("MOZ_ASSERT" "(" "EventCausesClickEvents(*aMouseUpEvent)"
")"); do { *((volatile int*)__null) = 6033; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6034 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"
, 6034); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 6034; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6035
6036 RefPtr<PresShell> presShell = mPresContext->GetPresShell();
6037 if (!presShell) {
6038 return NS_OK;
6039 }
6040
6041 nsCOMPtr<nsIContent> clickTarget =
6042 nsIContent::FromEventTargetOrNull(aMouseUpEvent->mClickTarget);
6043 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"
, 6043); return NS_ERROR_UNEXPECTED; } } while (false)
;
6044
6045 // Fire click events if the event target is still available.
6046 // Note that do not include the eMouseUp event's status since we ignore it
6047 // for compatibility with the other browsers.
6048 nsEventStatus status = nsEventStatus_eIgnore;
6049 nsresult rv = DispatchClickEvents(presShell, aMouseUpEvent, &status,
6050 clickTarget, aOverrideClickTarget);
6051 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"
, 6051)
) {
6052 return rv;
6053 }
6054
6055 // Do not do anything if preceding click events are consumed.
6056 // Note that Chromium dispatches "paste" event and actually pates clipboard
6057 // text into focused editor even if the preceding click events are consumed.
6058 // However, this is different from our traditional behavior and does not
6059 // conform to DOM events. If we need to keep compatibility with Chromium,
6060 // we should change it later.
6061 if (status == nsEventStatus_eConsumeNoDefault) {
6062 *aStatus = nsEventStatus_eConsumeNoDefault;
6063 return NS_OK;
6064 }
6065
6066 // Handle middle click paste if it's enabled and the mouse button is middle.
6067 if (aMouseUpEvent->mButton != MouseButton::eMiddle ||
6068 !WidgetMouseEvent::IsMiddleClickPasteEnabled()) {
6069 return NS_OK;
6070 }
6071 DebugOnly<nsresult> rvIgnored =
6072 HandleMiddleClickPaste(presShell, aMouseUpEvent, &status, nullptr);
6073 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"
, 6074); } } while (false)
6074 "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"
, 6074); } } while (false)
;
6075
6076 // If new status is nsEventStatus_eConsumeNoDefault or
6077 // nsEventStatus_eConsumeDoDefault, use it.
6078 if (*aStatus != nsEventStatus_eConsumeNoDefault &&
6079 (status == nsEventStatus_eConsumeNoDefault ||
6080 status == nsEventStatus_eConsumeDoDefault)) {
6081 *aStatus = status;
6082 }
6083
6084 // Don't return error even if middle mouse paste fails since we haven't
6085 // handled it here.
6086 return NS_OK;
6087}
6088
6089nsresult EventStateManager::DispatchClickEvents(
6090 PresShell* aPresShell, WidgetMouseEvent* aMouseUpEvent,
6091 nsEventStatus* aStatus, nsIContent* aClickTarget,
6092 nsIContent* aOverrideClickTarget) {
6093 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"
, 6093); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresShell"
")"); do { *((volatile int*)__null) = 6093; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6094 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"
, 6094); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpEvent"
")"); do { *((volatile int*)__null) = 6094; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6095 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"
, 6095); AnnotateMozCrashReason("MOZ_ASSERT" "(" "EventCausesClickEvents(*aMouseUpEvent)"
")"); do { *((volatile int*)__null) = 6095; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6096 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"
, 6096); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 6096; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6097 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"
, 6097); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aClickTarget || aOverrideClickTarget"
")"); do { *((volatile int*)__null) = 6097; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6098
6099 bool notDispatchToContents =
6100 (aMouseUpEvent->mButton == MouseButton::eMiddle ||
6101 aMouseUpEvent->mButton == MouseButton::eSecondary);
6102
6103 bool fireAuxClick = notDispatchToContents;
6104
6105 AutoWeakFrame currentTarget = aClickTarget->GetPrimaryFrame();
6106 nsresult rv = InitAndDispatchClickEvent(
6107 aMouseUpEvent, aStatus, ePointerClick, aPresShell, aClickTarget,
6108 currentTarget, notDispatchToContents, aOverrideClickTarget);
6109 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"
, 6109)
) {
6110 return rv;
6111 }
6112
6113 // Fire auxclick event if necessary.
6114 if (fireAuxClick && *aStatus != nsEventStatus_eConsumeNoDefault &&
6115 aClickTarget && aClickTarget->IsInComposedDoc()) {
6116 rv = InitAndDispatchClickEvent(aMouseUpEvent, aStatus, ePointerAuxClick,
6117 aPresShell, aClickTarget, currentTarget,
6118 false, aOverrideClickTarget);
6119 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"
, 6120); } } while (false)
6120 "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"
, 6120); } } while (false)
;
6121 }
6122
6123 // Fire double click event if click count is 2.
6124 if (aMouseUpEvent->mClickCount == 2 && !fireAuxClick && aClickTarget &&
6125 aClickTarget->IsInComposedDoc()) {
6126 rv = InitAndDispatchClickEvent(aMouseUpEvent, aStatus, eMouseDoubleClick,
6127 aPresShell, aClickTarget, currentTarget,
6128 notDispatchToContents, aOverrideClickTarget);
6129 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"
, 6129)
) {
6130 return rv;
6131 }
6132 }
6133
6134 return rv;
6135}
6136
6137nsresult EventStateManager::HandleMiddleClickPaste(
6138 PresShell* aPresShell, WidgetMouseEvent* aMouseEvent,
6139 nsEventStatus* aStatus, EditorBase* aEditorBase) {
6140 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"
, 6140); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresShell"
")"); do { *((volatile int*)__null) = 6140; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6141 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"
, 6141); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseEvent"
")"); do { *((volatile int*)__null) = 6141; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6142 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"
, 6144); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
")"); do { *((volatile int*)__null) = 6144; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6143 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"
, 6144); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
")"); do { *((volatile int*)__null) = 6144; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6144 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"
, 6144); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
")"); do { *((volatile int*)__null) = 6144; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6145 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"
, 6145); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 6145; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6146 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"
, 6146); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault"
")"); do { *((volatile int*)__null) = 6146; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6147
6148 // Even if we're called twice or more for a mouse operation, we should
6149 // handle only once. Although mMultipleActionsPrevented may be set to
6150 // true by different event handler in the future, we can use it for now.
6151 if (aMouseEvent->mFlags.mMultipleActionsPrevented) {
6152 return NS_OK;
6153 }
6154 aMouseEvent->mFlags.mMultipleActionsPrevented = true;
6155
6156 RefPtr<Selection> selection;
6157 if (aEditorBase) {
6158 selection = aEditorBase->GetSelection();
6159 if (NS_WARN_IF(!selection)NS_warn_if_impl(!selection, "!selection", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6159)
) {
6160 return NS_ERROR_FAILURE;
6161 }
6162 } else {
6163 Document* document = aPresShell->GetDocument();
6164 if (NS_WARN_IF(!document)NS_warn_if_impl(!document, "!document", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6164)
) {
6165 return NS_ERROR_FAILURE;
6166 }
6167 selection = nsCopySupport::GetSelectionForCopy(document);
6168 if (NS_WARN_IF(!selection)NS_warn_if_impl(!selection, "!selection", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6168)
) {
6169 return NS_ERROR_FAILURE;
6170 }
6171
6172 const nsRange* range = selection->GetRangeAt(0);
6173 if (range) {
6174 nsINode* target = range->GetStartContainer();
6175 if (target && target->OwnerDoc()->IsInChromeDocShell()) {
6176 // In Chrome document, limit middle-click pasting to only the editor
6177 // because it looks odd if pasting works in the focused editor when you
6178 // middle-click toolbar or something which are far from the editor.
6179 // However, as DevTools especially Web Console module assumes that paste
6180 // event will be fired when middle-click even on not editor, don't limit
6181 // it.
6182 return NS_OK;
6183 }
6184 }
6185 }
6186
6187 // Don't modify selection here because we've already set caret to the point
6188 // at "mousedown" event.
6189
6190 nsIClipboard::ClipboardType clipboardType = nsIClipboard::kGlobalClipboard;
6191 nsCOMPtr<nsIClipboard> clipboardService =
6192 do_GetService("@mozilla.org/widget/clipboard;1");
6193 if (clipboardService && clipboardService->IsClipboardTypeSupported(
6194 nsIClipboard::kSelectionClipboard)) {
6195 clipboardType = nsIClipboard::kSelectionClipboard;
6196 }
6197
6198 // Fire ePaste event by ourselves since we need to dispatch "paste" event
6199 // even if the middle click event was consumed for compatibility with
6200 // Chromium.
6201 if (!nsCopySupport::FireClipboardEvent(ePaste, Some(clipboardType),
6202 aPresShell, selection)) {
6203 *aStatus = nsEventStatus_eConsumeNoDefault;
6204 return NS_OK;
6205 }
6206
6207 // Although we've fired "paste" event, there is no editor to accept the
6208 // clipboard content.
6209 if (!aEditorBase) {
6210 return NS_OK;
6211 }
6212
6213 // Check if the editor is still the good target to paste.
6214 if (aEditorBase->Destroyed() || aEditorBase->IsReadonly()) {
6215 // XXX Should we consume the event when the editor is readonly and/or
6216 // disabled?
6217 return NS_OK;
6218 }
6219
6220 // The selection may have been modified during reflow. Therefore, we
6221 // should adjust event target to pass IsAcceptableInputEvent().
6222 const nsRange* range = selection->GetRangeAt(0);
6223 if (!range) {
6224 return NS_OK;
6225 }
6226 WidgetMouseEvent mouseEvent(*aMouseEvent);
6227 mouseEvent.mOriginalTarget = range->GetStartContainer();
6228 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"
, 6228)
||
6229 !aEditorBase->IsAcceptableInputEvent(&mouseEvent)) {
6230 return NS_OK;
6231 }
6232
6233 // If Control key is pressed, we should paste clipboard content as
6234 // quotation. Otherwise, paste it as is.
6235 if (aMouseEvent->IsControl()) {
6236 DebugOnly<nsresult> rv = aEditorBase->PasteAsQuotationAsAction(
6237 clipboardType, EditorBase::DispatchPasteEvent::No);
6238 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"
, 6238); } } while (false)
;
6239 } else {
6240 DebugOnly<nsresult> rv = aEditorBase->PasteAsAction(
6241 clipboardType, EditorBase::DispatchPasteEvent::No);
6242 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"
, 6242); } } while (false)
;
6243 }
6244 *aStatus = nsEventStatus_eConsumeNoDefault;
6245
6246 return NS_OK;
6247}
6248
6249void EventStateManager::ConsumeInteractionData(
6250 Record<nsString, dom::InteractionData>& aInteractions) {
6251 OnTypingInteractionEnded();
6252
6253 aInteractions.Entries().Clear();
6254 auto newEntry = aInteractions.Entries().AppendElement();
6255 newEntry->mKey = u"Typing"_ns;
6256 newEntry->mValue = gTypingInteraction;
6257 gTypingInteraction = {};
6258}
6259
6260nsIFrame* EventStateManager::GetEventTarget() {
6261 PresShell* presShell;
6262 if (mCurrentTarget || !mPresContext ||
6263 !(presShell = mPresContext->GetPresShell())) {
6264 return mCurrentTarget;
6265 }
6266
6267 if (mCurrentTargetContent) {
6268 mCurrentTarget = mPresContext->GetPrimaryFrameFor(mCurrentTargetContent);
6269 if (mCurrentTarget) {
6270 return mCurrentTarget;
6271 }
6272 }
6273
6274 nsIFrame* frame = presShell->GetCurrentEventFrame();
6275 return (mCurrentTarget = frame);
6276}
6277
6278already_AddRefed<nsIContent> EventStateManager::GetEventTargetContent(
6279 WidgetEvent* aEvent) {
6280 if (aEvent && (aEvent->mMessage == eFocus || aEvent->mMessage == eBlur)) {
6281 nsCOMPtr<nsIContent> content = GetFocusedElement();
6282 return content.forget();
6283 }
6284
6285 if (mCurrentTargetContent) {
6286 nsCOMPtr<nsIContent> content = mCurrentTargetContent;
6287 return content.forget();
6288 }
6289
6290 nsCOMPtr<nsIContent> content;
6291 if (PresShell* presShell = mPresContext->GetPresShell()) {
6292 content = presShell->GetEventTargetContent(aEvent);
6293 }
6294
6295 // Some events here may set mCurrentTarget but not set the corresponding
6296 // event target in the PresShell.
6297 if (!content && mCurrentTarget) {
6298 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(content));
6299 }
6300
6301 return content.forget();
6302}
6303
6304static Element* GetLabelTarget(nsIContent* aPossibleLabel) {
6305 mozilla::dom::HTMLLabelElement* label =
6306 mozilla::dom::HTMLLabelElement::FromNode(aPossibleLabel);
6307 if (!label) return nullptr;
6308
6309 return label->GetLabeledElement();
6310}
6311
6312/* static */
6313inline void EventStateManager::DoStateChange(Element* aElement,
6314 ElementState aState,
6315 bool aAddState) {
6316 if (aAddState) {
6317 aElement->AddStates(aState);
6318 } else {
6319 aElement->RemoveStates(aState);
6320 }
6321}
6322
6323/* static */
6324inline void EventStateManager::DoStateChange(nsIContent* aContent,
6325 ElementState aState,
6326 bool aStateAdded) {
6327 if (aContent->IsElement()) {
6328 DoStateChange(aContent->AsElement(), aState, aStateAdded);
6329 }
6330}
6331
6332/* static */
6333void EventStateManager::UpdateAncestorState(nsIContent* aStartNode,
6334 nsIContent* aStopBefore,
6335 ElementState aState,
6336 bool aAddState) {
6337 for (; aStartNode && aStartNode != aStopBefore;
6338 aStartNode = aStartNode->GetFlattenedTreeParent()) {
6339 // We might be starting with a non-element (e.g. a text node) and
6340 // if someone is doing something weird might be ending with a
6341 // non-element too (e.g. a document fragment)
6342 if (!aStartNode->IsElement()) {
6343 continue;
6344 }
6345 Element* element = aStartNode->AsElement();
6346 DoStateChange(element, aState, aAddState);
6347 Element* labelTarget = GetLabelTarget(element);
6348 if (labelTarget) {
6349 DoStateChange(labelTarget, aState, aAddState);
6350 }
6351 }
6352
6353 if (aAddState) {
6354 // We might be in a situation where a node was in hover both
6355 // because it was hovered and because the label for it was
6356 // hovered, and while we stopped hovering the node the label is
6357 // still hovered. Or we might have had two nested labels for the
6358 // same node, and while one is no longer hovered the other still
6359 // is. In that situation, the label that's still hovered will be
6360 // aStopBefore or some ancestor of it, and the call we just made
6361 // to UpdateAncestorState with aAddState = false would have
6362 // removed the hover state from the node. But the node should
6363 // still be in hover state. To handle this situation we need to
6364 // keep walking up the tree and any time we find a label mark its
6365 // corresponding node as still in our state.
6366 for (; aStartNode; aStartNode = aStartNode->GetFlattenedTreeParent()) {
6367 if (!aStartNode->IsElement()) {
6368 continue;
6369 }
6370
6371 Element* labelTarget = GetLabelTarget(aStartNode->AsElement());
6372 if (labelTarget && !labelTarget->State().HasState(aState)) {
6373 DoStateChange(labelTarget, aState, true);
6374 }
6375 }
6376 }
6377}
6378
6379// static
6380bool CanContentHaveActiveState(nsIContent& aContent) {
6381 // Editable content can never become active since their default actions
6382 // are disabled. Watch out for editable content in native anonymous
6383 // subtrees though, as they belong to text controls.
6384 return !aContent.IsEditable() || aContent.IsInNativeAnonymousSubtree();
6385}
6386
6387bool EventStateManager::SetContentState(nsIContent* aContent,
6388 ElementState aState) {
6389 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"
, 6389); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ManagesState(aState)"
") (" "Unexpected state" ")"); do { *((volatile int*)__null)
= 6389; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
6390
6391 nsCOMPtr<nsIContent> notifyContent1;
6392 nsCOMPtr<nsIContent> notifyContent2;
6393 bool updateAncestors;
6394
6395 if (aState == ElementState::HOVER || aState == ElementState::ACTIVE) {
6396 // Hover and active are hierarchical
6397 updateAncestors = true;
6398
6399 // check to see that this state is allowed by style. Check dragover too?
6400 // XXX Is this even what we want?
6401 if (mCurrentTarget &&
6402 mCurrentTarget->StyleUI()->UserInput() == StyleUserInput::None) {
6403 return false;
6404 }
6405
6406 if (aState == ElementState::ACTIVE) {
6407 if (aContent && !CanContentHaveActiveState(*aContent)) {
6408 aContent = nullptr;
6409 }
6410 if (aContent != mActiveContent) {
6411 notifyContent1 = aContent;
6412 notifyContent2 = mActiveContent;
6413 mActiveContent = aContent;
6414 }
6415 } else {
6416 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"
, 6416); MOZ_PretendNoReturn(); } } while (0)
;
6417 nsIContent* newHover;
6418
6419 if (mPresContext->IsDynamic()) {
6420 newHover = aContent;
6421 } else {
6422 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"
, 6424); MOZ_PretendNoReturn(); } } while (0)
6423 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"
, 6424); MOZ_PretendNoReturn(); } } while (0)
6424 "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"
, 6424); MOZ_PretendNoReturn(); } } while (0)
;
6425 nsIFrame* frame = aContent ? aContent->GetPrimaryFrame() : nullptr;
6426 if (frame && nsLayoutUtils::IsViewportScrollbarFrame(frame)) {
6427 // The scrollbars of viewport should not ignore the hover state.
6428 // Because they are *not* the content of the web page.
6429 newHover = aContent;
6430 } else {
6431 // All contents of the web page should ignore the hover state.
6432 newHover = nullptr;
6433 }
6434 }
6435
6436 if (newHover != mHoverContent) {
6437 notifyContent1 = newHover;
6438 notifyContent2 = mHoverContent;
6439 mHoverContent = newHover;
6440 }
6441 }
6442 } else {
6443 updateAncestors = false;
6444 if (aState == ElementState::DRAGOVER) {
6445 if (aContent != sDragOverContent) {
6446 notifyContent1 = aContent;
6447 notifyContent2 = sDragOverContent;
6448 sDragOverContent = aContent;
6449 }
6450 } else if (aState == ElementState::URLTARGET) {
6451 if (aContent != mURLTargetContent) {
6452 notifyContent1 = aContent;
6453 notifyContent2 = mURLTargetContent;
6454 mURLTargetContent = aContent;
6455 }
6456 }
6457 }
6458
6459 // We need to keep track of which of notifyContent1 and notifyContent2 is
6460 // getting the state set and which is getting it unset. If both are
6461 // non-null, then notifyContent1 is having the state set and notifyContent2
6462 // is having it unset. But if one of them is null, we need to keep track of
6463 // the right thing for notifyContent1 explicitly.
6464 bool content1StateSet = true;
6465 if (!notifyContent1) {
6466 // This is ok because FindCommonAncestor wouldn't find anything
6467 // anyway if notifyContent1 is null.
6468 notifyContent1 = notifyContent2;
6469 notifyContent2 = nullptr;
6470 content1StateSet = false;
6471 }
6472
6473 if (notifyContent1 && mPresContext) {
6474 EnsureDocument(mPresContext);
6475 if (mDocument) {
6476 nsAutoScriptBlocker scriptBlocker;
6477
6478 if (updateAncestors) {
6479 nsCOMPtr<nsIContent> commonAncestor =
6480 FindCommonAncestor(notifyContent1, notifyContent2);
6481 if (notifyContent2) {
6482 // It's very important to first notify the state removal and
6483 // then the state addition, because due to labels it's
6484 // possible that we're removing state from some element but
6485 // then adding it again (say because mHoverContent changed
6486 // from a control to its label).
6487 UpdateAncestorState(notifyContent2, commonAncestor, aState, false);
6488 }
6489 UpdateAncestorState(notifyContent1, commonAncestor, aState,
6490 content1StateSet);
6491 } else {
6492 if (notifyContent2) {
6493 DoStateChange(notifyContent2, aState, false);
6494 }
6495 DoStateChange(notifyContent1, aState, content1StateSet);
6496 }
6497 }
6498 }
6499
6500 return true;
6501}
6502
6503void EventStateManager::RemoveNodeFromChainIfNeeded(ElementState aState,
6504 nsIContent* aContentRemoved,
6505 bool aNotify) {
6506 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"
, 6506); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aState == ElementState::HOVER || aState == ElementState::ACTIVE"
")"); do { *((volatile int*)__null) = 6506; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6507 if (!aContentRemoved->IsElement() ||
6508 !aContentRemoved->AsElement()->State().HasState(aState)) {
6509 return;
6510 }
6511
6512 nsCOMPtr<nsIContent>& leaf =
6513 aState == ElementState::HOVER ? mHoverContent : mActiveContent;
6514
6515 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"
, 6515); AnnotateMozCrashReason("MOZ_ASSERT" "(" "leaf" ")");
do { *((volatile int*)__null) = 6515; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6516 // These two NS_ASSERTIONS below can fail for Shadow DOM sometimes, and it's
6517 // not clear how to best handle it, see
6518 // https://github.com/whatwg/html/issues/4795 and bug 1551621.
6519 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"
, 6521); MOZ_PretendNoReturn(); } } while (0)
6520 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"
, 6521); MOZ_PretendNoReturn(); } } while (0)
6521 "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"
, 6521); MOZ_PretendNoReturn(); } } while (0)
;
6522
6523 nsIContent* newLeaf = aContentRemoved->GetFlattenedTreeParent();
6524 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"
, 6524); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!newLeaf || newLeaf->IsElement()"
")"); do { *((volatile int*)__null) = 6524; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6525 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"
, 6526); MOZ_PretendNoReturn(); } } while (0)
6526 "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"
, 6526); MOZ_PretendNoReturn(); } } while (0)
;
6527 if (aNotify) {
6528 SetContentState(newLeaf, aState);
6529 } else {
6530 // We don't update the removed content's state here, since removing NAC
6531 // happens from layout and we don't really want to notify at that point or
6532 // what not.
6533 //
6534 // Also, NAC is not observable and NAC being removed will go away soon.
6535 leaf = newLeaf;
6536 }
6537 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"
, 6538); AnnotateMozCrashReason("MOZ_ASSERT" "(" "leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf && !CanContentHaveActiveState(*newLeaf))"
")"); do { *((volatile int*)__null) = 6538; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6538 !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"
, 6538); AnnotateMozCrashReason("MOZ_ASSERT" "(" "leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf && !CanContentHaveActiveState(*newLeaf))"
")"); do { *((volatile int*)__null) = 6538; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6539}
6540
6541void EventStateManager::NativeAnonymousContentRemoved(nsIContent* aContent) {
6542 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"
, 6542); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsRootOfNativeAnonymousSubtree()"
")"); do { *((volatile int*)__null) = 6542; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6543 RemoveNodeFromChainIfNeeded(ElementState::HOVER, aContent, false);
6544 RemoveNodeFromChainIfNeeded(ElementState::ACTIVE, aContent, false);
6545
6546 nsCOMPtr<nsIContent>& lastLeftMouseDownContent =
6547 mLastLeftMouseDownInfo.mLastMouseDownContent;
6548 if (lastLeftMouseDownContent &&
6549 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
6550 lastLeftMouseDownContent, aContent)) {
6551 lastLeftMouseDownContent = aContent->GetFlattenedTreeParent();
6552 }
6553
6554 nsCOMPtr<nsIContent>& lastMiddleMouseDownContent =
6555 mLastMiddleMouseDownInfo.mLastMouseDownContent;
6556 if (lastMiddleMouseDownContent &&
6557 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
6558 lastMiddleMouseDownContent, aContent)) {
6559 lastMiddleMouseDownContent = aContent->GetFlattenedTreeParent();
6560 }
6561
6562 nsCOMPtr<nsIContent>& lastRightMouseDownContent =
6563 mLastRightMouseDownInfo.mLastMouseDownContent;
6564 if (lastRightMouseDownContent &&
6565 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
6566 lastRightMouseDownContent, aContent)) {
6567 lastRightMouseDownContent = aContent->GetFlattenedTreeParent();
6568 }
6569}
6570
6571void EventStateManager::ContentRemoved(Document* aDocument,
6572 nsIContent* aContent) {
6573 /*
6574 * Anchor and area elements when focused or hovered might make the UI to show
6575 * the current link. We want to make sure that the UI gets informed when they
6576 * are actually removed from the DOM.
6577 */
6578 if (aContent->IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area) &&
6579 (aContent->AsElement()->State().HasAtLeastOneOfStates(
6580 ElementState::FOCUS | ElementState::HOVER))) {
6581 Element* element = aContent->AsElement();
6582 element->LeaveLink(element->GetPresContext(Element::eForComposedDoc));
6583 }
6584
6585 if (aContent->IsElement()) {
6586 if (RefPtr<nsPresContext> presContext = mPresContext) {
6587 IMEStateManager::OnRemoveContent(*presContext,
6588 MOZ_KnownLive(*aContent->AsElement())(*aContent->AsElement()));
6589 }
6590 WheelTransaction::OnRemoveElement(aContent);
6591 }
6592
6593 // inform the focus manager that the content is being removed. If this
6594 // content is focused, the focus will be removed without firing events.
6595 if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
6596 fm->ContentRemoved(aDocument, aContent);
6597 }
6598
6599 RemoveNodeFromChainIfNeeded(ElementState::HOVER, aContent, true);
6600 RemoveNodeFromChainIfNeeded(ElementState::ACTIVE, aContent, true);
6601
6602 if (sDragOverContent &&
6603 sDragOverContent->OwnerDoc() == aContent->OwnerDoc() &&
6604 nsContentUtils::ContentIsFlattenedTreeDescendantOf(sDragOverContent,
6605 aContent)) {
6606 sDragOverContent = nullptr;
6607 }
6608
6609 PointerEventHandler::ReleaseIfCaptureByDescendant(aContent);
6610
6611 if (mMouseEnterLeaveHelper) {
6612 const bool hadMouseOutTarget =
6613 mMouseEnterLeaveHelper->GetOutEventTarget() != nullptr;
6614 mMouseEnterLeaveHelper->ContentRemoved(*aContent);
6615 // If we lose the mouseout target, we need to dispatch mouseover on an
6616 // ancestor. For ensuring the chance to do it before next user input, we
6617 // need a synthetic mouse move.
6618 if (hadMouseOutTarget && !mMouseEnterLeaveHelper->GetOutEventTarget()) {
6619 if (PresShell* presShell =
6620 mPresContext ? mPresContext->GetPresShell() : nullptr) {
6621 presShell->SynthesizeMouseMove(false);
6622 }
6623 }
6624 }
6625 for (const auto& entry : mPointersEnterLeaveHelper) {
6626 if (entry.GetData()) {
6627 entry.GetData()->ContentRemoved(*aContent);
6628 }
6629 }
6630}
6631
6632void EventStateManager::TextControlRootWillBeRemoved(
6633 TextControlElement& aTextControlElement) {
6634 if (!mGestureDownInTextControl || !mGestureDownFrameOwner ||
6635 !mGestureDownFrameOwner->IsInNativeAnonymousSubtree()) {
6636 return;
6637 }
6638 // If we track gesture to start drag in aTextControlElement, we should keep
6639 // tracking it with aTextContrlElement itself for now because this may be
6640 // caused by reframing aTextControlElement which may not be intended by the
6641 // user.
6642 if (&aTextControlElement ==
6643 mGestureDownFrameOwner
6644 ->GetClosestNativeAnonymousSubtreeRootParentOrHost()) {
6645 mGestureDownFrameOwner = &aTextControlElement;
6646 }
6647}
6648
6649void EventStateManager::TextControlRootAdded(
6650 Element& aAnonymousDivElement, TextControlElement& aTextControlElement) {
6651 if (!mGestureDownInTextControl ||
6652 mGestureDownFrameOwner != &aTextControlElement) {
6653 return;
6654 }
6655 // If we track gesture to start drag in aTextControlElement, but the frame
6656 // owner is the text control element itself, the anonymous nodes in it are
6657 // recreated by a reframe. If so, we should keep tracking it with the
6658 // recreated native anonymous node.
6659 mGestureDownFrameOwner =
6660 aAnonymousDivElement.GetFirstChild()
6661 ? aAnonymousDivElement.GetFirstChild()
6662 : static_cast<nsIContent*>(&aAnonymousDivElement);
6663}
6664
6665bool EventStateManager::EventStatusOK(WidgetGUIEvent* aEvent) {
6666 return !(aEvent->mMessage == eMouseDown &&
6667 aEvent->AsMouseEvent()->mButton == MouseButton::ePrimary &&
6668 !sNormalLMouseEventInProcess);
6669}
6670
6671//-------------------------------------------
6672// Access Key Registration
6673//-------------------------------------------
6674void EventStateManager::RegisterAccessKey(Element* aElement, uint32_t aKey) {
6675 if (aElement && !mAccessKeys.Contains(aElement)) {
6676 mAccessKeys.AppendObject(aElement);
6677 }
6678}
6679
6680void EventStateManager::UnregisterAccessKey(Element* aElement, uint32_t aKey) {
6681 if (aElement) {
6682 mAccessKeys.RemoveObject(aElement);
6683 }
6684}
6685
6686uint32_t EventStateManager::GetRegisteredAccessKey(Element* aElement) {
6687 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"
, 6687); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aElement" ")"
); do { *((volatile int*)__null) = 6687; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6688
6689 if (!mAccessKeys.Contains(aElement)) {
6690 return 0;
6691 }
6692
6693 nsAutoString accessKey;
6694 aElement->GetAttr(nsGkAtoms::accesskey, accessKey);
6695 return accessKey.First();
6696}
6697
6698void EventStateManager::EnsureDocument(nsPresContext* aPresContext) {
6699 if (!mDocument) mDocument = aPresContext->Document();
6700}
6701
6702void EventStateManager::FlushLayout(nsPresContext* aPresContext) {
6703 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"
, 6703); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresContext"
") (" "nullptr ptr" ")"); do { *((volatile int*)__null) = 6703
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
6704 if (RefPtr<PresShell> presShell = aPresContext->GetPresShell()) {
6705 presShell->FlushPendingNotifications(FlushType::InterruptibleLayout);
6706 }
6707}
6708
6709Element* EventStateManager::GetFocusedElement() {
6710 nsFocusManager* fm = nsFocusManager::GetFocusManager();
6711 EnsureDocument(mPresContext);
6712 if (!fm || !mDocument) {
6713 return nullptr;
6714 }
6715
6716 nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
6717 return nsFocusManager::GetFocusedDescendant(
6718 mDocument->GetWindow(), nsFocusManager::eOnlyCurrentWindow,
6719 getter_AddRefs(focusedWindow));
6720}
6721
6722//-------------------------------------------------------
6723// Return true if the docshell is visible
6724
6725bool EventStateManager::IsShellVisible(nsIDocShell* aShell) {
6726 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"
, 6726); MOZ_PretendNoReturn(); } } while (0)
;
6727
6728 nsCOMPtr<nsIBaseWindow> basewin = do_QueryInterface(aShell);
6729 if (!basewin) return true;
6730
6731 bool isVisible = true;
6732 basewin->GetVisibility(&isVisible);
6733
6734 // We should be doing some additional checks here so that
6735 // we don't tab into hidden tabs of tabbrowser. -bryner
6736
6737 return isVisible;
6738}
6739
6740nsresult EventStateManager::DoContentCommandEvent(
6741 WidgetContentCommandEvent* aEvent) {
6742 EnsureDocument(mPresContext);
6743 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"
, 6743); return NS_ERROR_FAILURE; } } while (false)
;
6744 nsCOMPtr<nsPIDOMWindowOuter> window(mDocument->GetWindow());
6745 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"
, 6745); return NS_ERROR_FAILURE; } } while (false)
;
6746
6747 nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
6748 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"
, 6748); return NS_ERROR_FAILURE; } } while (false)
;
6749 const char* cmd;
6750 bool maybeNeedToHandleInRemote = false;
6751 switch (aEvent->mMessage) {
6752 case eContentCommandCut:
6753 cmd = "cmd_cut";
6754 maybeNeedToHandleInRemote = true;
6755 break;
6756 case eContentCommandCopy:
6757 cmd = "cmd_copy";
6758 maybeNeedToHandleInRemote = true;
6759 break;
6760 case eContentCommandPaste:
6761 cmd = "cmd_paste";
6762 maybeNeedToHandleInRemote = true;
6763 break;
6764 case eContentCommandDelete:
6765 cmd = "cmd_delete";
6766 maybeNeedToHandleInRemote = true;
6767 break;
6768 case eContentCommandUndo:
6769 cmd = "cmd_undo";
6770 maybeNeedToHandleInRemote = true;
6771 break;
6772 case eContentCommandRedo:
6773 cmd = "cmd_redo";
6774 maybeNeedToHandleInRemote = true;
6775 break;
6776 case eContentCommandPasteTransferable:
6777 cmd = "cmd_pasteTransferable";
6778 break;
6779 case eContentCommandLookUpDictionary:
6780 cmd = "cmd_lookUpDictionary";
6781 break;
6782 default:
6783 return NS_ERROR_NOT_IMPLEMENTED;
6784 }
6785 if (XRE_IsParentProcess() && maybeNeedToHandleInRemote) {
6786 if (BrowserParent* remote = BrowserParent::GetFocused()) {
6787 if (!aEvent->mOnlyEnabledCheck) {
6788 remote->SendSimpleContentCommandEvent(*aEvent);
6789 }
6790 // XXX The command may be disabled in the parent process. Perhaps, we
6791 // should set actual enabled state in the parent process here and there
6792 // should be another bool flag which indicates whether the content is sent
6793 // to a remote process.
6794 aEvent->mIsEnabled = true;
6795 aEvent->mSucceeded = true;
6796 return NS_OK;
6797 }
6798 }
6799 // If user tries to do something, user must try to do it in visible window.
6800 // So, let's retrieve controller of visible window.
6801 nsCOMPtr<nsIController> controller;
6802 nsresult rv =
6803 root->GetControllerForCommand(cmd, true, getter_AddRefs(controller));
6804 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"
, 6804); return rv; } } while (false)
;
6805 if (!controller) {
6806 // When GetControllerForCommand succeeded but there is no controller, the
6807 // command isn't supported.
6808 aEvent->mIsEnabled = false;
6809 } else {
6810 bool canDoIt;
6811 rv = controller->IsCommandEnabled(cmd, &canDoIt);
6812 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"
, 6812); return rv; } } while (false)
;
6813 aEvent->mIsEnabled = canDoIt;
6814 if (canDoIt && !aEvent->mOnlyEnabledCheck) {
6815 switch (aEvent->mMessage) {
6816 case eContentCommandPasteTransferable: {
6817 BrowserParent* remote = BrowserParent::GetFocused();
6818 if (remote) {
6819 IPCTransferable ipcTransferable;
6820 nsContentUtils::TransferableToIPCTransferable(
6821 aEvent->mTransferable, &ipcTransferable, false,
6822 remote->Manager());
6823 remote->SendPasteTransferable(std::move(ipcTransferable));
6824 rv = NS_OK;
6825 } else {
6826 nsCOMPtr<nsICommandController> commandController =
6827 do_QueryInterface(controller);
6828 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"
, 6828); return NS_ERROR_UNEXPECTED; } } while (false)
;
6829
6830 RefPtr<nsCommandParams> params = new nsCommandParams();
6831 rv = params->SetISupports("transferable", aEvent->mTransferable);
6832 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"
, 6832)
) {
6833 return rv;
6834 }
6835 rv = commandController->DoCommandWithParams(cmd, params);
6836 }
6837 break;
6838 }
6839
6840 case eContentCommandLookUpDictionary: {
6841 nsCOMPtr<nsICommandController> commandController =
6842 do_QueryInterface(controller);
6843 if (NS_WARN_IF(!commandController)NS_warn_if_impl(!commandController, "!commandController", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6843)
) {
6844 return NS_ERROR_FAILURE;
6845 }
6846
6847 RefPtr<nsCommandParams> params = new nsCommandParams();
6848 rv = params->SetInt("x", aEvent->mRefPoint.x);
6849 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"
, 6849)
) {
6850 return rv;
6851 }
6852
6853 rv = params->SetInt("y", aEvent->mRefPoint.y);
6854 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"
, 6854)
) {
6855 return rv;
6856 }
6857
6858 rv = commandController->DoCommandWithParams(cmd, params);
6859 break;
6860 }
6861
6862 default:
6863 rv = controller->DoCommand(cmd);
6864 break;
6865 }
6866 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"
, 6866); return rv; } } while (false)
;
6867 }
6868 }
6869 aEvent->mSucceeded = true;
6870 return NS_OK;
6871}
6872
6873nsresult EventStateManager::DoContentCommandInsertTextEvent(
6874 WidgetContentCommandEvent* aEvent) {
6875 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"
, 6875); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 6875; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6876 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"
, 6876); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eContentCommandInsertText"
")"); do { *((volatile int*)__null) = 6876; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6877 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"
, 6877); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aEvent->mString.isSome()"
")"); do { *((volatile int*)__null) = 6877; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6878 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"
, 6878); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!aEvent->mString.ref().IsEmpty()"
")"); do { *((volatile int*)__null) = 6878; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6879
6880 aEvent->mIsEnabled = false;
6881 aEvent->mSucceeded = false;
6882
6883 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"
, 6883); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
6884
6885 if (XRE_IsParentProcess()) {
6886 // Handle it in focused content process if there is.
6887 if (BrowserParent* remote = BrowserParent::GetFocused()) {
6888 if (!aEvent->mOnlyEnabledCheck) {
6889 remote->SendInsertText(*aEvent);
6890 }
6891 // XXX The remote process may be not editable right now. Therefore, this
6892 // may be different from actual state in the remote process.
6893 aEvent->mIsEnabled = true;
6894 aEvent->mSucceeded = true;
6895 return NS_OK;
6896 }
6897 }
6898
6899 // If there is no active editor in this process, we should treat the command
6900 // is disabled.
6901 RefPtr<EditorBase> activeEditor =
6902 nsContentUtils::GetActiveEditor(mPresContext);
6903 if (!activeEditor) {
6904 aEvent->mSucceeded = true;
6905 return NS_OK;
6906 }
6907
6908 nsresult rv = activeEditor->InsertTextAsAction(aEvent->mString.ref());
6909 aEvent->mIsEnabled = rv != NS_SUCCESS_DOM_NO_OPERATION;
6910 aEvent->mSucceeded = NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)));
6911 return NS_OK;
6912}
6913
6914nsresult EventStateManager::DoContentCommandReplaceTextEvent(
6915 WidgetContentCommandEvent* aEvent) {
6916 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"
, 6916); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 6916; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6917 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"
, 6917); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eContentCommandReplaceText"
")"); do { *((volatile int*)__null) = 6917; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6918 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"
, 6918); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aEvent->mString.isSome()"
")"); do { *((volatile int*)__null) = 6918; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6919 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"
, 6919); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!aEvent->mString.ref().IsEmpty()"
")"); do { *((volatile int*)__null) = 6919; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6920
6921 aEvent->mIsEnabled = false;
6922 aEvent->mSucceeded = false;
6923
6924 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"
, 6924); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
6925
6926 if (XRE_IsParentProcess()) {
6927 // Handle it in focused content process if there is.
6928 if (BrowserParent* remote = BrowserParent::GetFocused()) {
6929 if (!aEvent->mOnlyEnabledCheck) {
6930 Unused << remote->SendReplaceText(*aEvent);
6931 }
6932 // XXX The remote process may be not editable right now. Therefore, this
6933 // may be different from actual state in the remote process.
6934 aEvent->mIsEnabled = true;
6935 aEvent->mSucceeded = true;
6936 return NS_OK;
6937 }
6938 }
6939
6940 // If there is no active editor in this process, we should treat the command
6941 // is disabled.
6942 RefPtr<EditorBase> activeEditor =
6943 nsContentUtils::GetActiveEditor(mPresContext);
6944 if (NS_WARN_IF(!activeEditor)NS_warn_if_impl(!activeEditor, "!activeEditor", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6944)
) {
6945 aEvent->mSucceeded = true;
6946 return NS_OK;
6947 }
6948
6949 RefPtr<TextComposition> composition =
6950 IMEStateManager::GetTextCompositionFor(mPresContext);
6951 if (NS_WARN_IF(composition)NS_warn_if_impl(composition, "composition", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6951)
) {
6952 // We don't support replace text action during composition.
6953 aEvent->mSucceeded = true;
6954 return NS_OK;
6955 }
6956
6957 ContentEventHandler handler(mPresContext);
6958 RefPtr<nsRange> range = handler.GetRangeFromFlatTextOffset(
6959 aEvent, aEvent->mSelection.mOffset,
6960 aEvent->mSelection.mReplaceSrcString.Length());
6961 if (NS_WARN_IF(!range)NS_warn_if_impl(!range, "!range", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6961)
) {
6962 aEvent->mSucceeded = false;
6963 return NS_OK;
6964 }
6965
6966 // If original replacement text isn't matched with selection text, throws
6967 // error.
6968 nsAutoString targetStr;
6969 nsresult rv = handler.GenerateFlatTextContent(range, targetStr);
6970 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"
, 6970)
) {
6971 aEvent->mSucceeded = false;
6972 return NS_OK;
6973 }
6974 if (!aEvent->mSelection.mReplaceSrcString.Equals(targetStr)) {
6975 aEvent->mSucceeded = false;
6976 return NS_OK;
6977 }
6978
6979 rv = activeEditor->ReplaceTextAsAction(
6980 aEvent->mString.ref(), range,
6981 TextEditor::AllowBeforeInputEventCancelable::Yes,
6982 aEvent->mSelection.mPreventSetSelection
6983 ? EditorBase::PreventSetSelection::Yes
6984 : EditorBase::PreventSetSelection::No);
6985 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"
, 6985)
) {
6986 aEvent->mSucceeded = false;
6987 return NS_OK;
6988 }
6989
6990 aEvent->mIsEnabled = rv != NS_SUCCESS_DOM_NO_OPERATION;
6991 aEvent->mSucceeded = true;
6992 return NS_OK;
6993}
6994
6995nsresult EventStateManager::DoContentCommandScrollEvent(
6996 WidgetContentCommandEvent* aEvent) {
6997 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"
, 6997); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
6998 PresShell* presShell = mPresContext->GetPresShell();
6999 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"
, 6999); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
7000 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"
, 7000); return NS_ERROR_INVALID_ARG; } } while (false)
;
7001
7002 ScrollUnit scrollUnit;
7003 switch (aEvent->mScroll.mUnit) {
7004 case WidgetContentCommandEvent::eCmdScrollUnit_Line:
7005 scrollUnit = ScrollUnit::LINES;
7006 break;
7007 case WidgetContentCommandEvent::eCmdScrollUnit_Page:
7008 scrollUnit = ScrollUnit::PAGES;
7009 break;
7010 case WidgetContentCommandEvent::eCmdScrollUnit_Whole:
7011 scrollUnit = ScrollUnit::WHOLE;
7012 break;
7013 default:
7014 return NS_ERROR_INVALID_ARG;
7015 }
7016
7017 aEvent->mSucceeded = true;
7018
7019 ScrollContainerFrame* sf =
7020 presShell->GetScrollContainerFrameToScroll(layers::EitherScrollDirection);
7021 aEvent->mIsEnabled =
7022 sf ? (aEvent->mScroll.mIsHorizontal ? WheelHandlingUtils::CanScrollOn(
7023 sf, aEvent->mScroll.mAmount, 0)
7024 : WheelHandlingUtils::CanScrollOn(
7025 sf, 0, aEvent->mScroll.mAmount))
7026 : false;
7027
7028 if (!aEvent->mIsEnabled || aEvent->mOnlyEnabledCheck) {
7029 return NS_OK;
7030 }
7031
7032 nsIntPoint pt(0, 0);
7033 if (aEvent->mScroll.mIsHorizontal) {
7034 pt.x = aEvent->mScroll.mAmount;
7035 } else {
7036 pt.y = aEvent->mScroll.mAmount;
7037 }
7038
7039 // The caller may want synchronous scrolling.
7040 sf->ScrollBy(pt, scrollUnit, ScrollMode::Instant);
7041 return NS_OK;
7042}
7043
7044void EventStateManager::SetActiveManager(EventStateManager* aNewESM,
7045 nsIContent* aContent) {
7046 if (sActiveESM && aNewESM != sActiveESM) {
7047 sActiveESM->SetContentState(nullptr, ElementState::ACTIVE);
7048 }
7049 sActiveESM = aNewESM;
7050 if (sActiveESM && aContent) {
7051 sActiveESM->SetContentState(aContent, ElementState::ACTIVE);
7052 }
7053}
7054
7055void EventStateManager::ClearGlobalActiveContent(EventStateManager* aClearer) {
7056 if (aClearer) {
7057 aClearer->SetContentState(nullptr, ElementState::ACTIVE);
7058 if (sDragOverContent) {
7059 aClearer->SetContentState(nullptr, ElementState::DRAGOVER);
7060 }
7061 }
7062 if (sActiveESM && aClearer != sActiveESM) {
7063 sActiveESM->SetContentState(nullptr, ElementState::ACTIVE);
7064 }
7065 sActiveESM = nullptr;
7066}
7067
7068/******************************************************************/
7069/* mozilla::EventStateManager::DeltaAccumulator */
7070/******************************************************************/
7071
7072void EventStateManager::DeltaAccumulator::InitLineOrPageDelta(
7073 nsIFrame* aTargetFrame, EventStateManager* aESM, WidgetWheelEvent* aEvent) {
7074 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"
, 7074); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aESM" ")");
do { *((volatile int*)__null) = 7074; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7075 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"
, 7075); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 7075; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7076
7077 // Reset if the previous wheel event is too old.
7078 if (!mLastTime.IsNull()) {
7079 TimeDuration duration = TimeStamp::Now() - mLastTime;
7080 if (duration.ToMilliseconds() >
7081 StaticPrefs::mousewheel_transaction_timeout()) {
7082 Reset();
7083 }
7084 }
7085 // If we have accumulated delta, we may need to reset it.
7086 if (IsInTransaction()) {
7087 // If wheel event type is changed, reset the values.
7088 if (mHandlingDeltaMode != aEvent->mDeltaMode ||
7089 mIsNoLineOrPageDeltaDevice != aEvent->mIsNoLineOrPageDelta) {
7090 Reset();
7091 } else {
7092 // If the delta direction is changed, we should reset only the
7093 // accumulated values.
7094 if (mX && aEvent->mDeltaX && ((aEvent->mDeltaX > 0.0) != (mX > 0.0))) {
7095 mX = mPendingScrollAmountX = 0.0;
7096 }
7097 if (mY && aEvent->mDeltaY && ((aEvent->mDeltaY > 0.0) != (mY > 0.0))) {
7098 mY = mPendingScrollAmountY = 0.0;
7099 }
7100 }
7101 }
7102
7103 mHandlingDeltaMode = aEvent->mDeltaMode;
7104 mIsNoLineOrPageDeltaDevice = aEvent->mIsNoLineOrPageDelta;
7105
7106 {
7107 ScrollContainerFrame* scrollTarget = aESM->ComputeScrollTarget(
7108 aTargetFrame, aEvent, COMPUTE_DEFAULT_ACTION_TARGET);
7109 nsPresContext* pc = scrollTarget ? scrollTarget->PresContext()
7110 : aTargetFrame->PresContext();
7111 aEvent->mScrollAmount = aESM->GetScrollAmount(pc, aEvent, scrollTarget);
7112 }
7113
7114 // If it's handling neither a device that does not provide line or page deltas
7115 // nor delta values multiplied by prefs, we must not modify lineOrPageDelta
7116 // values.
7117 // TODO(emilio): Does this care about overridden scroll speed?
7118 if (!mIsNoLineOrPageDeltaDevice &&
7119 !EventStateManager::WheelPrefs::GetInstance()
7120 ->NeedToComputeLineOrPageDelta(aEvent)) {
7121 // Set the delta values to mX and mY. They would be used when above block
7122 // resets mX/mY/mPendingScrollAmountX/mPendingScrollAmountY if the direction
7123 // is changed.
7124 // NOTE: We shouldn't accumulate the delta values, it might could cause
7125 // overflow even though it's not a realistic situation.
7126 if (aEvent->mDeltaX) {
7127 mX = aEvent->mDeltaX;
7128 }
7129 if (aEvent->mDeltaY) {
7130 mY = aEvent->mDeltaY;
7131 }
7132 mLastTime = TimeStamp::Now();
7133 return;
7134 }
7135
7136 mX += aEvent->mDeltaX;
7137 mY += aEvent->mDeltaY;
7138
7139 if (mHandlingDeltaMode == WheelEvent_Binding::DOM_DELTA_PIXEL) {
7140 // Records pixel delta values and init mLineOrPageDeltaX and
7141 // mLineOrPageDeltaY for wheel events which are caused by pixel only
7142 // devices. Ignore mouse wheel transaction for computing this. The
7143 // lineOrPageDelta values will be used by dispatching legacy
7144 // eMouseScrollEventClass (DOMMouseScroll) but not be used for scrolling
7145 // of default action. The transaction should be used only for the default
7146 // action.
7147 auto scrollAmountInCSSPixels =
7148 CSSIntSize::FromAppUnitsRounded(aEvent->mScrollAmount);
7149
7150 aEvent->mLineOrPageDeltaX = RoundDown(mX) / scrollAmountInCSSPixels.width;
7151 aEvent->mLineOrPageDeltaY = RoundDown(mY) / scrollAmountInCSSPixels.height;
7152
7153 mX -= aEvent->mLineOrPageDeltaX * scrollAmountInCSSPixels.width;
7154 mY -= aEvent->mLineOrPageDeltaY * scrollAmountInCSSPixels.height;
7155 } else {
7156 aEvent->mLineOrPageDeltaX = RoundDown(mX);
7157 aEvent->mLineOrPageDeltaY = RoundDown(mY);
7158 mX -= aEvent->mLineOrPageDeltaX;
7159 mY -= aEvent->mLineOrPageDeltaY;
7160 }
7161
7162 mLastTime = TimeStamp::Now();
7163}
7164
7165void EventStateManager::DeltaAccumulator::Reset() {
7166 mX = mY = 0.0;
7167 mPendingScrollAmountX = mPendingScrollAmountY = 0.0;
7168 mHandlingDeltaMode = UINT32_MAX(4294967295U);
7169 mIsNoLineOrPageDeltaDevice = false;
7170}
7171
7172nsIntPoint
7173EventStateManager::DeltaAccumulator::ComputeScrollAmountForDefaultAction(
7174 WidgetWheelEvent* aEvent, const nsIntSize& aScrollAmountInDevPixels) {
7175 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"
, 7175); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 7175; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7176
7177 DeltaValues acceleratedDelta = WheelTransaction::AccelerateWheelDelta(aEvent);
7178
7179 nsIntPoint result(0, 0);
7180 if (aEvent->mDeltaMode == WheelEvent_Binding::DOM_DELTA_PIXEL) {
7181 mPendingScrollAmountX += acceleratedDelta.deltaX;
7182 mPendingScrollAmountY += acceleratedDelta.deltaY;
7183 } else {
7184 mPendingScrollAmountX +=
7185 aScrollAmountInDevPixels.width * acceleratedDelta.deltaX;
7186 mPendingScrollAmountY +=
7187 aScrollAmountInDevPixels.height * acceleratedDelta.deltaY;
7188 }
7189 result.x = RoundDown(mPendingScrollAmountX);
7190 result.y = RoundDown(mPendingScrollAmountY);
7191 mPendingScrollAmountX -= result.x;
7192 mPendingScrollAmountY -= result.y;
7193
7194 return result;
7195}
7196
7197/******************************************************************/
7198/* mozilla::EventStateManager::WheelPrefs */
7199/******************************************************************/
7200
7201// static
7202EventStateManager::WheelPrefs* EventStateManager::WheelPrefs::GetInstance() {
7203 if (!sInstance) {
7204 sInstance = new WheelPrefs();
7205 }
7206 return sInstance;
7207}
7208
7209// static
7210void EventStateManager::WheelPrefs::Shutdown() {
7211 delete sInstance;
7212 sInstance = nullptr;
7213}
7214
7215// static
7216void EventStateManager::WheelPrefs::OnPrefChanged(const char* aPrefName,
7217 void* aClosure) {
7218 // forget all prefs, it's not problem for performance.
7219 sInstance->Reset();
7220 DeltaAccumulator::GetInstance()->Reset();
7221}
7222
7223EventStateManager::WheelPrefs::WheelPrefs() {
7224 Reset();
7225 Preferences::RegisterPrefixCallback(OnPrefChanged, "mousewheel.");
7226}
7227
7228EventStateManager::WheelPrefs::~WheelPrefs() {
7229 Preferences::UnregisterPrefixCallback(OnPrefChanged, "mousewheel.");
7230}
7231
7232void EventStateManager::WheelPrefs::Reset() { memset(mInit, 0, sizeof(mInit)); }
7233
7234EventStateManager::WheelPrefs::Index EventStateManager::WheelPrefs::GetIndexFor(
7235 const WidgetWheelEvent* aEvent) {
7236 if (!aEvent) {
7237 return INDEX_DEFAULT;
7238 }
7239
7240 Modifiers modifiers = (aEvent->mModifiers & (MODIFIER_ALT | MODIFIER_CONTROL |
7241 MODIFIER_META | MODIFIER_SHIFT));
7242
7243 switch (modifiers) {
7244 case MODIFIER_ALT:
7245 return INDEX_ALT;
7246 case MODIFIER_CONTROL:
7247 return INDEX_CONTROL;
7248 case MODIFIER_META:
7249 return INDEX_META;
7250 case MODIFIER_SHIFT:
7251 return INDEX_SHIFT;
7252 default:
7253 // If two or more modifier keys are pressed, we should use default
7254 // settings.
7255 return INDEX_DEFAULT;
7256 }
7257}
7258
7259void EventStateManager::WheelPrefs::GetBasePrefName(
7260 EventStateManager::WheelPrefs::Index aIndex, nsACString& aBasePrefName) {
7261 aBasePrefName.AssignLiteral("mousewheel.");
7262 switch (aIndex) {
7263 case INDEX_ALT:
7264 aBasePrefName.AppendLiteral("with_alt.");
7265 break;
7266 case INDEX_CONTROL:
7267 aBasePrefName.AppendLiteral("with_control.");
7268 break;
7269 case INDEX_META:
7270 aBasePrefName.AppendLiteral("with_meta.");
7271 break;
7272 case INDEX_SHIFT:
7273 aBasePrefName.AppendLiteral("with_shift.");
7274 break;
7275 case INDEX_DEFAULT:
7276 default:
7277 aBasePrefName.AppendLiteral("default.");
7278 break;
7279 }
7280}
7281
7282void EventStateManager::WheelPrefs::Init(
7283 EventStateManager::WheelPrefs::Index aIndex) {
7284 if (mInit[aIndex]) {
7285 return;
7286 }
7287 mInit[aIndex] = true;
7288
7289 nsAutoCString basePrefName;
7290 GetBasePrefName(aIndex, basePrefName);
7291
7292 nsAutoCString prefNameX(basePrefName);
7293 prefNameX.AppendLiteral("delta_multiplier_x");
7294 mMultiplierX[aIndex] =
7295 static_cast<double>(Preferences::GetInt(prefNameX.get(), 100)) / 100;
7296
7297 nsAutoCString prefNameY(basePrefName);
7298 prefNameY.AppendLiteral("delta_multiplier_y");
7299 mMultiplierY[aIndex] =
7300 static_cast<double>(Preferences::GetInt(prefNameY.get(), 100)) / 100;
7301
7302 nsAutoCString prefNameZ(basePrefName);
7303 prefNameZ.AppendLiteral("delta_multiplier_z");
7304 mMultiplierZ[aIndex] =
7305 static_cast<double>(Preferences::GetInt(prefNameZ.get(), 100)) / 100;
7306
7307 nsAutoCString prefNameAction(basePrefName);
7308 prefNameAction.AppendLiteral("action");
7309 int32_t action = Preferences::GetInt(prefNameAction.get(), ACTION_SCROLL);
7310 if (action < int32_t(ACTION_NONE) || action > int32_t(ACTION_LAST)) {
7311 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"
, 7311)
;
7312 action = ACTION_SCROLL;
7313 }
7314 mActions[aIndex] = static_cast<Action>(action);
7315
7316 // Compute action values overridden by .override_x pref.
7317 // At present, override is possible only for the x-direction
7318 // because this pref is introduced mainly for tilt wheels.
7319 // Note that ACTION_HORIZONTALIZED_SCROLL isn't a valid value for this pref
7320 // because it affects only to deltaY.
7321 prefNameAction.AppendLiteral(".override_x");
7322 int32_t actionOverrideX = Preferences::GetInt(prefNameAction.get(), -1);
7323 if (actionOverrideX < -1 || actionOverrideX > int32_t(ACTION_LAST) ||
7324 actionOverrideX == ACTION_HORIZONTALIZED_SCROLL) {
7325 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"
, 7325)
;
7326 actionOverrideX = -1;
7327 }
7328 mOverriddenActionsX[aIndex] = (actionOverrideX == -1)
7329 ? static_cast<Action>(action)
7330 : static_cast<Action>(actionOverrideX);
7331}
7332
7333void EventStateManager::WheelPrefs::GetMultiplierForDeltaXAndY(
7334 const WidgetWheelEvent* aEvent, Index aIndex, double* aMultiplierForDeltaX,
7335 double* aMultiplierForDeltaY) {
7336 *aMultiplierForDeltaX = mMultiplierX[aIndex];
7337 *aMultiplierForDeltaY = mMultiplierY[aIndex];
7338 // If the event has been horizontalized(I.e. treated as a horizontal wheel
7339 // scroll for a vertical wheel scroll), then we should swap mMultiplierX and
7340 // mMultiplierY. By doing this, multipliers will still apply to the delta
7341 // values they origianlly corresponded to.
7342 if (aEvent->mDeltaValuesHorizontalizedForDefaultHandler &&
7343 ComputeActionFor(aEvent) == ACTION_HORIZONTALIZED_SCROLL) {
7344 std::swap(*aMultiplierForDeltaX, *aMultiplierForDeltaY);
7345 }
7346}
7347
7348void EventStateManager::WheelPrefs::ApplyUserPrefsToDelta(
7349 WidgetWheelEvent* aEvent) {
7350 if (aEvent->mCustomizedByUserPrefs) {
7351 return;
7352 }
7353
7354 Index index = GetIndexFor(aEvent);
7355 Init(index);
7356
7357 double multiplierForDeltaX = 1.0, multiplierForDeltaY = 1.0;
7358 GetMultiplierForDeltaXAndY(aEvent, index, &multiplierForDeltaX,
7359 &multiplierForDeltaY);
7360 aEvent->mDeltaX *= multiplierForDeltaX;
7361 aEvent->mDeltaY *= multiplierForDeltaY;
7362 aEvent->mDeltaZ *= mMultiplierZ[index];
7363
7364 // If the multiplier is 1.0 or -1.0, i.e., it doesn't change the absolute
7365 // value, we should use lineOrPageDelta values which were set by widget.
7366 // Otherwise, we need to compute them from accumulated delta values.
7367 if (!NeedToComputeLineOrPageDelta(aEvent)) {
7368 aEvent->mLineOrPageDeltaX *= static_cast<int32_t>(multiplierForDeltaX);
7369 aEvent->mLineOrPageDeltaY *= static_cast<int32_t>(multiplierForDeltaY);
7370 } else {
7371 aEvent->mLineOrPageDeltaX = 0;
7372 aEvent->mLineOrPageDeltaY = 0;
7373 }
7374
7375 aEvent->mCustomizedByUserPrefs =
7376 ((mMultiplierX[index] != 1.0) || (mMultiplierY[index] != 1.0) ||
7377 (mMultiplierZ[index] != 1.0));
7378}
7379
7380void EventStateManager::WheelPrefs::CancelApplyingUserPrefsFromOverflowDelta(
7381 WidgetWheelEvent* aEvent) {
7382 Index index = GetIndexFor(aEvent);
7383 Init(index);
7384
7385 // XXX If the multiplier pref value is negative, the scroll direction was
7386 // changed and caused to scroll different direction. In such case,
7387 // this method reverts the sign of overflowDelta. Does it make widget
7388 // happy? Although, widget can know the pref applied delta values by
7389 // referrencing the deltaX and deltaY of the event.
7390
7391 double multiplierForDeltaX = 1.0, multiplierForDeltaY = 1.0;
7392 GetMultiplierForDeltaXAndY(aEvent, index, &multiplierForDeltaX,
7393 &multiplierForDeltaY);
7394 if (multiplierForDeltaX) {
7395 aEvent->mOverflowDeltaX /= multiplierForDeltaX;
7396 }
7397 if (multiplierForDeltaY) {
7398 aEvent->mOverflowDeltaY /= multiplierForDeltaY;
7399 }
7400}
7401
7402EventStateManager::WheelPrefs::Action
7403EventStateManager::WheelPrefs::ComputeActionFor(
7404 const WidgetWheelEvent* aEvent) {
7405 Index index = GetIndexFor(aEvent);
7406 Init(index);
7407
7408 bool deltaXPreferred = (Abs(aEvent->mDeltaX) > Abs(aEvent->mDeltaY) &&
7409 Abs(aEvent->mDeltaX) > Abs(aEvent->mDeltaZ));
7410 Action* actions = deltaXPreferred ? mOverriddenActionsX : mActions;
7411 if (actions[index] == ACTION_NONE || actions[index] == ACTION_SCROLL ||
7412 actions[index] == ACTION_HORIZONTALIZED_SCROLL) {
7413 return actions[index];
7414 }
7415
7416 // Momentum events shouldn't run special actions.
7417 if (aEvent->mIsMomentum) {
7418 // Use the default action. Note that user might kill the wheel scrolling.
7419 Init(INDEX_DEFAULT);
7420 if (actions[INDEX_DEFAULT] == ACTION_SCROLL ||
7421 actions[INDEX_DEFAULT] == ACTION_HORIZONTALIZED_SCROLL) {
7422 return actions[INDEX_DEFAULT];
7423 }
7424 return ACTION_NONE;
7425 }
7426
7427 return actions[index];
7428}
7429
7430bool EventStateManager::WheelPrefs::NeedToComputeLineOrPageDelta(
7431 const WidgetWheelEvent* aEvent) {
7432 Index index = GetIndexFor(aEvent);
7433 Init(index);
7434
7435 return (mMultiplierX[index] != 1.0 && mMultiplierX[index] != -1.0) ||
7436 (mMultiplierY[index] != 1.0 && mMultiplierY[index] != -1.0);
7437}
7438
7439void EventStateManager::WheelPrefs::GetUserPrefsForEvent(
7440 const WidgetWheelEvent* aEvent, double* aOutMultiplierX,
7441 double* aOutMultiplierY) {
7442 Index index = GetIndexFor(aEvent);
7443 Init(index);
7444
7445 double multiplierForDeltaX = 1.0, multiplierForDeltaY = 1.0;
7446 GetMultiplierForDeltaXAndY(aEvent, index, &multiplierForDeltaX,
7447 &multiplierForDeltaY);
7448 *aOutMultiplierX = multiplierForDeltaX;
7449 *aOutMultiplierY = multiplierForDeltaY;
7450}
7451
7452// static
7453Maybe<layers::APZWheelAction> EventStateManager::APZWheelActionFor(
7454 const WidgetWheelEvent* aEvent) {
7455 if (aEvent->mMessage != eWheel) {
7456 return Nothing();
7457 }
7458 WheelPrefs::Action action =
7459 WheelPrefs::GetInstance()->ComputeActionFor(aEvent);
7460 switch (action) {
7461 case WheelPrefs::ACTION_SCROLL:
7462 case WheelPrefs::ACTION_HORIZONTALIZED_SCROLL:
7463 return Some(layers::APZWheelAction::Scroll);
7464 case WheelPrefs::ACTION_PINCH_ZOOM:
7465 return Some(layers::APZWheelAction::PinchZoom);
7466 default:
7467 return Nothing();
7468 }
7469}
7470
7471// static
7472WheelDeltaAdjustmentStrategy EventStateManager::GetWheelDeltaAdjustmentStrategy(
7473 const WidgetWheelEvent& aEvent) {
7474 if (aEvent.mMessage != eWheel) {
7475 return WheelDeltaAdjustmentStrategy::eNone;
7476 }
7477 switch (WheelPrefs::GetInstance()->ComputeActionFor(&aEvent)) {
7478 case WheelPrefs::ACTION_SCROLL:
7479 if (StaticPrefs::mousewheel_autodir_enabled() && 0 == aEvent.mDeltaZ) {
7480 if (StaticPrefs::mousewheel_autodir_honourroot()) {
7481 return WheelDeltaAdjustmentStrategy::eAutoDirWithRootHonour;
7482 }
7483 return WheelDeltaAdjustmentStrategy::eAutoDir;
7484 }
7485 return WheelDeltaAdjustmentStrategy::eNone;
7486 case WheelPrefs::ACTION_HORIZONTALIZED_SCROLL:
7487 return WheelDeltaAdjustmentStrategy::eHorizontalize;
7488 default:
7489 break;
7490 }
7491 return WheelDeltaAdjustmentStrategy::eNone;
7492}
7493
7494void EventStateManager::GetUserPrefsForWheelEvent(
7495 const WidgetWheelEvent* aEvent, double* aOutMultiplierX,
7496 double* aOutMultiplierY) {
7497 WheelPrefs::GetInstance()->GetUserPrefsForEvent(aEvent, aOutMultiplierX,
7498 aOutMultiplierY);
7499}
7500
7501bool EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedX(
7502 const WidgetWheelEvent* aEvent) {
7503 Index index = GetIndexFor(aEvent);
7504 Init(index);
7505 return Abs(mMultiplierX[index]) >=
7506 MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
7507}
7508
7509bool EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedY(
7510 const WidgetWheelEvent* aEvent) {
7511 Index index = GetIndexFor(aEvent);
7512 Init(index);
7513 return Abs(mMultiplierY[index]) >=
7514 MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
7515}
7516
7517} // namespace mozilla