Bug Summary

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