Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name EventStateManager.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/events -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/events -resource-dir /usr/lib/llvm-19/lib/clang/19 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /var/lib/jenkins/workspace/firefox-scan-build/dom/events -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/events -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /var/lib/jenkins/workspace/firefox-scan-build/ipc/chromium/src -I /var/lib/jenkins/workspace/firefox-scan-build/docshell/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/html -I /var/lib/jenkins/workspace/firefox-scan-build/dom/storage -I /var/lib/jenkins/workspace/firefox-scan-build/dom/xml -I /var/lib/jenkins/workspace/firefox-scan-build/dom/xul -I /var/lib/jenkins/workspace/firefox-scan-build/js/xpconnect/wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/layout/forms -I /var/lib/jenkins/workspace/firefox-scan-build/layout/generic -I /var/lib/jenkins/workspace/firefox-scan-build/layout/xul -I /var/lib/jenkins/workspace/firefox-scan-build/layout/xul/tree -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-09-22-115206-3586786-1 -x c++ /var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp

/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp

1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#include "EventStateManager.h"
8
9#include "mozilla/AsyncEventDispatcher.h"
10#include "mozilla/Attributes.h"
11#include "mozilla/EditorBase.h"
12#include "mozilla/EventDispatcher.h"
13#include "mozilla/EventForwards.h"
14#include "mozilla/Hal.h"
15#include "mozilla/HTMLEditor.h"
16#include "mozilla/IMEStateManager.h"
17#include "mozilla/Likely.h"
18#include "mozilla/FocusModel.h"
19#include "mozilla/MiscEvents.h"
20#include "mozilla/MathAlgorithms.h"
21#include "mozilla/MouseEvents.h"
22#include "mozilla/PointerLockManager.h"
23#include "mozilla/PresShell.h"
24#include "mozilla/ScopeExit.h"
25#include "mozilla/ScrollTypes.h"
26#include "mozilla/TextComposition.h"
27#include "mozilla/TextControlElement.h"
28#include "mozilla/TextEditor.h"
29#include "mozilla/TextEvents.h"
30#include "mozilla/TouchEvents.h"
31#include "mozilla/Telemetry.h"
32#include "mozilla/UniquePtr.h"
33#include "mozilla/dom/BrowserBridgeChild.h"
34#include "mozilla/dom/BrowsingContext.h"
35#include "mozilla/dom/CanonicalBrowsingContext.h"
36#include "mozilla/dom/ContentChild.h"
37#include "mozilla/dom/DOMIntersectionObserver.h"
38#include "mozilla/dom/DragEvent.h"
39#include "mozilla/dom/Event.h"
40#include "mozilla/dom/FrameLoaderBinding.h"
41#include "mozilla/dom/HTMLLabelElement.h"
42#include "mozilla/dom/HTMLInputElement.h"
43#include "mozilla/dom/MouseEventBinding.h"
44#include "mozilla/dom/BrowserChild.h"
45#include "mozilla/dom/PointerEventHandler.h"
46#include "mozilla/dom/UIEvent.h"
47#include "mozilla/dom/UIEventBinding.h"
48#include "mozilla/dom/UserActivation.h"
49#include "mozilla/dom/WheelEventBinding.h"
50#include "mozilla/glean/GleanMetrics.h"
51#include "mozilla/ScrollContainerFrame.h"
52#include "mozilla/StaticPrefs_accessibility.h"
53#include "mozilla/StaticPrefs_browser.h"
54#include "mozilla/StaticPrefs_dom.h"
55#include "mozilla/StaticPrefs_layout.h"
56#include "mozilla/StaticPrefs_mousewheel.h"
57#include "mozilla/StaticPrefs_ui.h"
58#include "mozilla/StaticPrefs_zoom.h"
59
60#include "ContentEventHandler.h"
61#include "IMEContentObserver.h"
62#include "WheelHandlingHelper.h"
63#include "RemoteDragStartData.h"
64
65#include "nsCommandParams.h"
66#include "nsCOMPtr.h"
67#include "nsCopySupport.h"
68#include "nsFocusManager.h"
69#include "nsGenericHTMLElement.h"
70#include "nsIClipboard.h"
71#include "nsIContent.h"
72#include "nsIContentInlines.h"
73#include "mozilla/dom/Document.h"
74#include "nsICookieJarSettings.h"
75#include "nsIFrame.h"
76#include "nsFrameLoaderOwner.h"
77#include "nsIWeakReferenceUtils.h"
78#include "nsIWidget.h"
79#include "nsLiteralString.h"
80#include "nsPresContext.h"
81#include "nsTArray.h"
82#include "nsGkAtoms.h"
83#include "nsIFormControl.h"
84#include "nsComboboxControlFrame.h"
85#include "nsIDOMXULControlElement.h"
86#include "nsNameSpaceManager.h"
87#include "nsIBaseWindow.h"
88#include "nsFrameSelection.h"
89#include "nsPIDOMWindow.h"
90#include "nsPIWindowRoot.h"
91#include "nsIWebNavigation.h"
92#include "nsIDocumentViewer.h"
93#include "nsFrameManager.h"
94#include "nsIBrowserChild.h"
95#include "nsMenuPopupFrame.h"
96
97#include "nsIObserverService.h"
98#include "nsIDocShell.h"
99
100#include "nsSubDocumentFrame.h"
101#include "nsLayoutUtils.h"
102#include "nsIInterfaceRequestorUtils.h"
103#include "nsUnicharUtils.h"
104#include "nsContentUtils.h"
105
106#include "imgIContainer.h"
107#include "nsIProperties.h"
108#include "nsISupportsPrimitives.h"
109
110#include "nsServiceManagerUtils.h"
111#include "nsITimer.h"
112#include "nsFontMetrics.h"
113#include "nsIDragService.h"
114#include "nsIDragSession.h"
115#include "mozilla/dom/DataTransfer.h"
116#include "nsContentAreaDragDrop.h"
117#include "nsTreeBodyFrame.h"
118#include "nsIController.h"
119#include "mozilla/Services.h"
120#include "mozilla/dom/ContentParent.h"
121#include "mozilla/dom/Record.h"
122#include "mozilla/dom/Selection.h"
123
124#include "mozilla/Preferences.h"
125#include "mozilla/LookAndFeel.h"
126#include "mozilla/ProfilerLabels.h"
127#include "Units.h"
128
129#ifdef XP_MACOSX
130# import <ApplicationServices/ApplicationServices.h>
131#endif
132
133namespace mozilla {
134
135using namespace dom;
136
137static const LayoutDeviceIntPoint kInvalidRefPoint =
138 LayoutDeviceIntPoint(-1, -1);
139
140static uint32_t gMouseOrKeyboardEventCounter = 0;
141static nsITimer* gUserInteractionTimer = nullptr;
142static nsITimerCallback* gUserInteractionTimerCallback = nullptr;
143
144static const double kCursorLoadingTimeout = 1000; // ms
145static AutoWeakFrame gLastCursorSourceFrame;
146static TimeStamp gLastCursorUpdateTime;
147static TimeStamp gTypingStartTime;
148static TimeStamp gTypingEndTime;
149static int32_t gTypingInteractionKeyPresses = 0;
150static dom::InteractionData gTypingInteraction = {};
151
152static inline int32_t RoundDown(double aDouble) {
153 return (aDouble > 0) ? static_cast<int32_t>(floor(aDouble))
154 : static_cast<int32_t>(ceil(aDouble));
155}
156
157static bool IsSelectingLink(nsIFrame* aTargetFrame) {
158 if (!aTargetFrame) {
159 return false;
160 }
161 const nsFrameSelection* frameSel = aTargetFrame->GetConstFrameSelection();
162 if (!frameSel || !frameSel->GetDragState()) {
163 return false;
164 }
165
166 if (!nsContentUtils::GetClosestLinkInFlatTree(aTargetFrame->GetContent())) {
167 return false;
168 }
169 return true;
170}
171
172static UniquePtr<WidgetMouseEvent> CreateMouseOrPointerWidgetEvent(
173 WidgetMouseEvent* aMouseEvent, EventMessage aMessage,
174 EventTarget* aRelatedTarget);
175
176/**
177 * Returns the common ancestor for mouseup purpose, given the
178 * current mouseup target and the previous mousedown target.
179 */
180static nsINode* GetCommonAncestorForMouseUp(
181 nsINode* aCurrentMouseUpTarget, nsINode* aLastMouseDownTarget,
182 Maybe<FormControlType>& aLastMouseDownInputControlType) {
183 if (!aCurrentMouseUpTarget || !aLastMouseDownTarget) {
184 return nullptr;
185 }
186
187 if (aCurrentMouseUpTarget == aLastMouseDownTarget) {
188 return aCurrentMouseUpTarget;
189 }
190
191 // Build the chain of parents
192 AutoTArray<nsINode*, 30> parents1;
193 do {
194 parents1.AppendElement(aCurrentMouseUpTarget);
195 aCurrentMouseUpTarget = aCurrentMouseUpTarget->GetFlattenedTreeParentNode();
196 } while (aCurrentMouseUpTarget);
197
198 AutoTArray<nsINode*, 30> parents2;
199 do {
200 parents2.AppendElement(aLastMouseDownTarget);
201 if (aLastMouseDownTarget == parents1.LastElement()) {
202 break;
203 }
204 aLastMouseDownTarget = aLastMouseDownTarget->GetFlattenedTreeParentNode();
205 } while (aLastMouseDownTarget);
206
207 // Find where the parent chain differs
208 uint32_t pos1 = parents1.Length();
209 uint32_t pos2 = parents2.Length();
210 nsINode* parent = nullptr;
211 for (uint32_t len = std::min(pos1, pos2); len > 0; --len) {
212 nsINode* child1 = parents1.ElementAt(--pos1);
213 nsINode* child2 = parents2.ElementAt(--pos2);
214 if (child1 != child2) {
215 break;
216 }
217
218 // If the input control type is different between mouseup and mousedown,
219 // this is not a valid click.
220 if (HTMLInputElement* input = HTMLInputElement::FromNodeOrNull(child1)) {
221 if (aLastMouseDownInputControlType.isSome() &&
222 aLastMouseDownInputControlType.ref() != input->ControlType()) {
223 break;
224 }
225 }
226 parent = child1;
227 }
228
229 return parent;
230}
231
232LazyLogModule sMouseBoundaryLog("MouseBoundaryEvents");
233LazyLogModule sPointerBoundaryLog("PointerBoundaryEvents");
234
235/******************************************************************/
236/* mozilla::UITimerCallback */
237/******************************************************************/
238
239class UITimerCallback final : public nsITimerCallback, public nsINamed {
240 public:
241 UITimerCallback() : mPreviousCount(0) {}
242 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
243 NS_DECL_NSITIMERCALLBACKvirtual nsresult Notify(nsITimer *timer) override; inline void
_ensure_GetName_exists(void) { static_assert(std::is_convertible
<decltype(this), nsINamed*>::value, "nsITimerCallback implementations must also implement nsINamed"
); }
244 NS_DECL_NSINAMEDvirtual nsresult GetName(nsACString& aName) override;
245 private:
246 ~UITimerCallback() = default;
247 uint32_t mPreviousCount;
248};
249
250NS_IMPL_ISUPPORTS(UITimerCallback, nsITimerCallback, nsINamed)MozExternalRefCountType UITimerCallback::AddRef(void) { static_assert
(!std::is_destructible_v<UITimerCallback>, "Reference-counted class "
"UITimerCallback" " should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
250; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("UITimerCallback" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("UITimerCallback" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"UITimerCallback\" != nullptr" " (" "Must specify a name" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"UITimerCallback\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 250; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("UITimerCallback" " not thread-safe"); nsrefcnt
count = ++mRefCnt; NS_LogAddRef((this), (count), ("UITimerCallback"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
UITimerCallback::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 250
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("UITimerCallback" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("UITimerCallback" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"UITimerCallback\" != nullptr" " (" "Must specify a name" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"UITimerCallback\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 250; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("UITimerCallback" " not thread-safe"); const
char* const nametmp = "UITimerCallback"; nsrefcnt count = --
mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count
== 0) { mRefCnt = 1; delete (this); return 0; } return count
; } nsresult UITimerCallback::QueryInterface(const nsIID&
aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<UITimerCallback, nsITimerCallback>, int32_t
( reinterpret_cast<char*>(static_cast<nsITimerCallback
*>((UITimerCallback*)0x1000)) - reinterpret_cast<char*>
((UITimerCallback*)0x1000))}, {&mozilla::detail::kImplementedIID
<UITimerCallback, nsINamed>, int32_t( reinterpret_cast<
char*>(static_cast<nsINamed*>((UITimerCallback*)0x1000
)) - reinterpret_cast<char*>((UITimerCallback*)0x1000))
}, {&mozilla::detail::kImplementedIID<UITimerCallback,
nsISupports>, int32_t(reinterpret_cast<char*>(static_cast
<nsISupports*>( static_cast<nsITimerCallback*>((UITimerCallback
*)0x1000))) - reinterpret_cast<char*>((UITimerCallback*
)0x1000))}, { nullptr, 0 } } ; static_assert((sizeof(table) /
sizeof(table[0])) > 1, "need at least 1 interface"); rv =
NS_TableDrivenQI(static_cast<void*>(this), aIID, aInstancePtr
, table); return rv; }
251
252// If aTimer is nullptr, this method always sends "user-interaction-inactive"
253// notification.
254NS_IMETHODIMPnsresult
255UITimerCallback::Notify(nsITimer* aTimer) {
256 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
257 if (!obs) return NS_ERROR_FAILURE;
258 if ((gMouseOrKeyboardEventCounter == mPreviousCount) || !aTimer) {
259 gMouseOrKeyboardEventCounter = 0;
260 obs->NotifyObservers(nullptr, "user-interaction-inactive", nullptr);
261 if (gUserInteractionTimer) {
262 gUserInteractionTimer->Cancel();
263 NS_RELEASE(gUserInteractionTimer)do { (gUserInteractionTimer)->Release(); (gUserInteractionTimer
) = 0; } while (0)
;
264 }
265 } else {
266 obs->NotifyObservers(nullptr, "user-interaction-active", nullptr);
267 EventStateManager::UpdateUserActivityTimer();
268
269 if (XRE_IsParentProcess()) {
270 hal::BatteryInformation batteryInfo;
271 hal::GetCurrentBatteryInformation(&batteryInfo);
272 glean::power_battery::percentage_when_user_active.AccumulateSingleSample(
273 uint64_t(batteryInfo.level() * 100));
274 }
275 }
276 mPreviousCount = gMouseOrKeyboardEventCounter;
277 return NS_OK;
278}
279
280NS_IMETHODIMPnsresult
281UITimerCallback::GetName(nsACString& aName) {
282 aName.AssignLiteral("UITimerCallback_timer");
283 return NS_OK;
284}
285
286/******************************************************************/
287/* mozilla::OverOutElementsWrapper */
288/******************************************************************/
289
290NS_IMPL_CYCLE_COLLECTION(OverOutElementsWrapper, mDeepestEnterEventTarget,OverOutElementsWrapper::cycleCollection OverOutElementsWrapper
::_cycleCollectorGlobal; void OverOutElementsWrapper::cycleCollection
::Unlink(void* p) { OverOutElementsWrapper* tmp = DowncastCCParticipant
<OverOutElementsWrapper>(p); ImplCycleCollectionUnlink(
tmp->mDeepestEnterEventTarget); ImplCycleCollectionUnlink(
tmp->mDispatchingOverEventTarget); ImplCycleCollectionUnlink
(tmp->mDispatchingOutOrDeepestLeaveEventTarget); (void)tmp
; } nsresult OverOutElementsWrapper::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { OverOutElementsWrapper
* tmp = DowncastCCParticipant<OverOutElementsWrapper>(p
); cb.DescribeRefCountedNode(tmp->mRefCnt.get(), "OverOutElementsWrapper"
); ImplCycleCollectionTraverse(cb, tmp->mDeepestEnterEventTarget
, "mDeepestEnterEventTarget", 0); ImplCycleCollectionTraverse
(cb, tmp->mDispatchingOverEventTarget, "mDispatchingOverEventTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDispatchingOutOrDeepestLeaveEventTarget
, "mDispatchingOutOrDeepestLeaveEventTarget", 0); (void)tmp; return
NS_OK; }
291 mDispatchingOverEventTarget,OverOutElementsWrapper::cycleCollection OverOutElementsWrapper
::_cycleCollectorGlobal; void OverOutElementsWrapper::cycleCollection
::Unlink(void* p) { OverOutElementsWrapper* tmp = DowncastCCParticipant
<OverOutElementsWrapper>(p); ImplCycleCollectionUnlink(
tmp->mDeepestEnterEventTarget); ImplCycleCollectionUnlink(
tmp->mDispatchingOverEventTarget); ImplCycleCollectionUnlink
(tmp->mDispatchingOutOrDeepestLeaveEventTarget); (void)tmp
; } nsresult OverOutElementsWrapper::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { OverOutElementsWrapper
* tmp = DowncastCCParticipant<OverOutElementsWrapper>(p
); cb.DescribeRefCountedNode(tmp->mRefCnt.get(), "OverOutElementsWrapper"
); ImplCycleCollectionTraverse(cb, tmp->mDeepestEnterEventTarget
, "mDeepestEnterEventTarget", 0); ImplCycleCollectionTraverse
(cb, tmp->mDispatchingOverEventTarget, "mDispatchingOverEventTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDispatchingOutOrDeepestLeaveEventTarget
, "mDispatchingOutOrDeepestLeaveEventTarget", 0); (void)tmp; return
NS_OK; }
292 mDispatchingOutOrDeepestLeaveEventTarget)OverOutElementsWrapper::cycleCollection OverOutElementsWrapper
::_cycleCollectorGlobal; void OverOutElementsWrapper::cycleCollection
::Unlink(void* p) { OverOutElementsWrapper* tmp = DowncastCCParticipant
<OverOutElementsWrapper>(p); ImplCycleCollectionUnlink(
tmp->mDeepestEnterEventTarget); ImplCycleCollectionUnlink(
tmp->mDispatchingOverEventTarget); ImplCycleCollectionUnlink
(tmp->mDispatchingOutOrDeepestLeaveEventTarget); (void)tmp
; } nsresult OverOutElementsWrapper::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { OverOutElementsWrapper
* tmp = DowncastCCParticipant<OverOutElementsWrapper>(p
); cb.DescribeRefCountedNode(tmp->mRefCnt.get(), "OverOutElementsWrapper"
); ImplCycleCollectionTraverse(cb, tmp->mDeepestEnterEventTarget
, "mDeepestEnterEventTarget", 0); ImplCycleCollectionTraverse
(cb, tmp->mDispatchingOverEventTarget, "mDispatchingOverEventTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDispatchingOutOrDeepestLeaveEventTarget
, "mDispatchingOutOrDeepestLeaveEventTarget", 0); (void)tmp; return
NS_OK; }
293NS_IMPL_CYCLE_COLLECTING_ADDREF(OverOutElementsWrapper)MozExternalRefCountType OverOutElementsWrapper::AddRef(void) {
static_assert(!std::is_destructible_v<OverOutElementsWrapper
>, "Reference-counted class " "OverOutElementsWrapper" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 293); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
293; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); _mOwningThread.AssertOwnership("OverOutElementsWrapper"
" not thread-safe"); nsISupports* base = OverOutElementsWrapper
::cycleCollection::Upcast(this); nsrefcnt count = mRefCnt.incr
(base); NS_LogAddRef((this), (count), ("OverOutElementsWrapper"
), (uint32_t)(sizeof(*this))); return count; }
294NS_IMPL_CYCLE_COLLECTING_RELEASE(OverOutElementsWrapper)MozExternalRefCountType OverOutElementsWrapper::Release(void)
{ do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 294); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 294
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); _mOwningThread.AssertOwnership("OverOutElementsWrapper"
" not thread-safe"); nsISupports* base = OverOutElementsWrapper
::cycleCollection::Upcast(this); nsrefcnt count = mRefCnt.decr
(base); NS_LogRelease((this), (count), ("OverOutElementsWrapper"
)); return count; } void OverOutElementsWrapper::DeleteCycleCollectable
(void) { delete (this); }
295
296NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(OverOutElementsWrapper)nsresult OverOutElementsWrapper::QueryInterface(const nsIID&
aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 296); MOZ_PretendNoReturn(); } } while (0); nsISupports* foundInterface
; if (TopThreeWordsEquals( aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID), (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID)) && (LowWordEquals(aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID)) || LowWordEquals(aIID, (nsCycleCollectionISupports::COMTypeInfo
<nsCycleCollectionISupports, void>::kIID)))) { if (LowWordEquals
(aIID, (nsXPCOMCycleCollectionParticipant::COMTypeInfo<nsXPCOMCycleCollectionParticipant
, void>::kIID))) { *aInstancePtr = OverOutElementsWrapper::
cycleCollection::GetParticipant(); return NS_OK; } if (LowWordEquals
(aIID, (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID))) { *aInstancePtr = OverOutElementsWrapper::
cycleCollection::Upcast(this); return NS_OK; } foundInterface
= nullptr; } else
297 NS_INTERFACE_MAP_ENTRY(nsISupports)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupports>)) foundInterface = static_cast
<nsISupports*>(this); else
298NS_INTERFACE_MAP_ENDfoundInterface = 0; nsresult status; if (!foundInterface) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(!aIID.Equals((nsISupports::COMTypeInfo<nsISupports
, void>::kIID)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aIID.Equals((nsISupports::COMTypeInfo
<nsISupports, void>::kIID))))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 298); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
")"); do { *((volatile int*)__null) = 298; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); status = NS_NOINTERFACE
; } else { (foundInterface)->AddRef(); status = NS_OK; } *
aInstancePtr = foundInterface; return status; }
299
300already_AddRefed<nsIWidget> OverOutElementsWrapper::GetLastOverWidget() const {
301 nsCOMPtr<nsIWidget> widget = do_QueryReferent(mLastOverWidget);
302 return widget.forget();
303}
304
305void OverOutElementsWrapper::ContentRemoved(nsIContent& aContent) {
306 if (!mDeepestEnterEventTarget) {
307 return;
308 }
309
310 if (!nsContentUtils::ContentIsFlattenedTreeDescendantOf(
311 mDeepestEnterEventTarget, &aContent)) {
312 return;
313 }
314
315 LogModule* const logModule = mType == BoundaryEventType::Mouse
316 ? sMouseBoundaryLog
317 : sPointerBoundaryLog;
318
319 if (!StaticPrefs::
320 dom_events_mouse_pointer_boundary_keep_enter_targets_after_over_target_removed()) {
321 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"over\" event target (%p) is removed"
, mDeepestEnterEventTarget.get()); } } while (0)
322 ("The last \"over\" event target (%p) is removed",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"over\" event target (%p) is removed"
, mDeepestEnterEventTarget.get()); } } while (0)
323 mDeepestEnterEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"over\" event target (%p) is removed"
, mDeepestEnterEventTarget.get()); } } while (0)
;
324 StoreOverEventTargetAndDeepestEnterEventTarget(nullptr);
325 return;
326 }
327
328 if (mDispatchingOverEventTarget &&
329 (mDeepestEnterEventTarget == mDispatchingOverEventTarget ||
330 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
331 mDispatchingOverEventTarget, &aContent))) {
332 if (mDispatchingOverEventTarget ==
333 mDispatchingOutOrDeepestLeaveEventTarget) {
334 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
335 ("The dispatching \"%s\" event target (%p) is removed",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
336 LastOverEventTargetIsOutEventTarget() ? "out" : "leave",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
337 mDispatchingOutOrDeepestLeaveEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
;
338 mDispatchingOutOrDeepestLeaveEventTarget = nullptr;
339 }
340 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"over\" event target (%p) is removed"
, mDispatchingOverEventTarget.get()); } } while (0)
341 ("The dispatching \"over\" event target (%p) is removed",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"over\" event target (%p) is removed"
, mDispatchingOverEventTarget.get()); } } while (0)
342 mDispatchingOverEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"over\" event target (%p) is removed"
, mDispatchingOverEventTarget.get()); } } while (0)
;
343 mDispatchingOverEventTarget = nullptr;
344 }
345 if (mDispatchingOutOrDeepestLeaveEventTarget &&
346 (mDeepestEnterEventTarget == mDispatchingOutOrDeepestLeaveEventTarget ||
347 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
348 mDispatchingOutOrDeepestLeaveEventTarget, &aContent))) {
349 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
350 ("The dispatching \"%s\" event target (%p) is removed",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
351 LastOverEventTargetIsOutEventTarget() ? "out" : "leave",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
352 mDispatchingOutOrDeepestLeaveEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
;
353 mDispatchingOutOrDeepestLeaveEventTarget = nullptr;
354 }
355 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
356 ("The last \"%s\" event target (%p) is removed and now the last "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
357 "deepest enter target becomes %s(%p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
358 LastOverEventTargetIsOutEventTarget() ? "over" : "enter",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
359 mDeepestEnterEventTarget.get(),do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
360 aContent.GetFlattenedTreeParent()do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
361 ? ToString(*aContent.GetFlattenedTreeParent()).c_str()do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
362 : "nullptr",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
363 aContent.GetFlattenedTreeParent()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
;
364 UpdateDeepestEnterEventTarget(aContent.GetFlattenedTreeParent());
365}
366
367void OverOutElementsWrapper::TryToRestorePendingRemovedOverTarget(
368 const WidgetEvent* aEvent) {
369 if (!MaybeHasPendingRemovingOverEventTarget()) {
370 return;
371 }
372
373 LogModule* const logModule = mType == BoundaryEventType::Mouse
374 ? sMouseBoundaryLog
375 : sPointerBoundaryLog;
376
377 // If we receive a mouse event immediately, let's try to restore the last
378 // "over" event target as the following "out" event target. We assume that a
379 // synthesized mousemove or another mouse event is being dispatched at latest
380 // the next animation frame from the removal. However, synthesized mouse move
381 // which is enqueued by ContentRemoved() may not sent to this instance because
382 // the target is considered with the latest layout, so the document of this
383 // instance may be moved somewhere before the next animation frame.
384 // Therefore, we should not restore the last "over" target if we receive an
385 // unexpected event like a keyboard event, a wheel event, etc.
386 if (aEvent->AsMouseEvent()) {
387 // Restore the original "over" event target should be allowed only when it's
388 // reconnected under the last deepest "enter" event target because we need
389 // to dispatch "leave" events later at least on the ancestors which have
390 // never been removed from the tree.
391 // XXX If new ancestor is inserted between mDeepestEnterEventTarget and
392 // mPendingToRemoveLastOverEventTarget, we will dispatch "leave" event even
393 // though we have not dispatched "enter" event on the element. For fixing
394 // this, we need to store the full path of the last "out" event target when
395 // it's removed from the tree. I guess we can be relax for this issue
396 // because this hack is required for web apps which reconnect the target
397 // to the same position immediately.
398 // XXX Should be IsInclusiveFlatTreeDescendantOf()? However, it may
399 // be reconnected into a subtree which is different from where the
400 // last over element was.
401 nsCOMPtr<nsIContent> pendingRemovingOverEventTarget =
402 GetPendingRemovingOverEventTarget();
403 if (pendingRemovingOverEventTarget &&
404 pendingRemovingOverEventTarget->IsInclusiveDescendantOf(
405 mDeepestEnterEventTarget)) {
406 // StoreOverEventTargetAndDeepestEnterEventTarget() always resets
407 // mLastOverWidget. When we restore the pending removing "over" event
408 // target, we need to keep storing the original "over" widget too.
409 nsCOMPtr<nsIWeakReference> widget = std::move(mLastOverWidget);
410 StoreOverEventTargetAndDeepestEnterEventTarget(
411 pendingRemovingOverEventTarget);
412 mLastOverWidget = std::move(widget);
413 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
414 ("The \"over\" event target (%p) is restored",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
415 mDeepestEnterEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
;
416 return;
417 }
418 MOZ_LOG(logModule, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
419 ("Forgetting the last \"over\" event target (%p) because it is not "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
420 "reconnected under the deepest enter event target (%p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
421 mPendingRemovingOverEventTarget.get(),do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
422 mDeepestEnterEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
;
423 } else {
424 MOZ_LOG(logModule, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
425 ("Forgetting the last \"over\" event target (%p) because an "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
426 "unexpected event (%s) is being dispatched, that means that "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
427 "EventStateManager didn't receive a synthesized mousemove which "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
428 "should be dispatched at next animation frame from the removal",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
429 mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage)))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
;
430 }
431
432 // Now, we should not restore mPendingRemovingOverEventTarget to
433 // mDeepestEnterEventTarget anymore since mPendingRemovingOverEventTarget was
434 // moved outside the subtree of mDeepestEnterEventTarget.
435 mPendingRemovingOverEventTarget = nullptr;
436}
437
438void OverOutElementsWrapper::WillDispatchOverAndEnterEvent(
439 nsIContent* aOverEventTarget) {
440 StoreOverEventTargetAndDeepestEnterEventTarget(aOverEventTarget);
441 // Store the first "over" event target we fire and don't refire "over" event
442 // to that element while the first "over" event is still ongoing.
443 mDispatchingOverEventTarget = aOverEventTarget;
444}
445
446void OverOutElementsWrapper::DidDispatchOverAndEnterEvent(
447 nsIContent* aOriginalOverTargetInComposedDoc,
448 nsIWidget* aOverEventTargetWidget) {
449 mDispatchingOverEventTarget = nullptr;
450 mLastOverWidget = do_GetWeakReference(aOverEventTargetWidget);
451
452 // Pointer Events define that once the `pointerover` event target is removed
453 // from the tree, `pointerout` should not be fired on that and the closest
454 // connected ancestor at the target removal should be kept as the deepest
455 // `pointerleave` target. Therefore, we don't need the special handling for
456 // `pointerout` event target if the last `pointerover` target is temporarily
457 // removed from the tree.
458 if (mType == OverOutElementsWrapper::BoundaryEventType::Pointer) {
459 return;
460 }
461
462 // Assume that the caller checks whether aOriginalOverTarget is in the
463 // original document. If we don't enable the strict mouse/pointer event
464 // boundary event dispatching by the pref (see below),
465 // mDeepestEnterEventTarget is set to nullptr when the last "over" target is
466 // removed. Therefore, we cannot check whether aOriginalOverTarget is in the
467 // original document here.
468 if (!aOriginalOverTargetInComposedDoc) {
469 return;
470 }
471 MOZ_ASSERT_IF(mDeepestEnterEventTarget,do { if (mDeepestEnterEventTarget) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mDeepestEnterEventTarget
->GetComposedDoc() == aOriginalOverTargetInComposedDoc->
GetComposedDoc())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget->
GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
")"); do { *((volatile int*)__null) = 473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
472 mDeepestEnterEventTarget->GetComposedDoc() ==do { if (mDeepestEnterEventTarget) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mDeepestEnterEventTarget
->GetComposedDoc() == aOriginalOverTargetInComposedDoc->
GetComposedDoc())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget->
GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
")"); do { *((volatile int*)__null) = 473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
473 aOriginalOverTargetInComposedDoc->GetComposedDoc())do { if (mDeepestEnterEventTarget) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mDeepestEnterEventTarget
->GetComposedDoc() == aOriginalOverTargetInComposedDoc->
GetComposedDoc())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget->
GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
")"); do { *((volatile int*)__null) = 473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
474 // If the "mouseover" event target is removed temporarily while we're
475 // dispatching "mouseover" and "mouseenter" events and the target gets back
476 // under the deepest enter event target, we should restore the "mouseover"
477 // target.
478 if ((!StaticPrefs::
479 dom_events_mouse_pointer_boundary_keep_enter_targets_after_over_target_removed() &&
480 !mDeepestEnterEventTarget) ||
481 (!LastOverEventTargetIsOutEventTarget() && mDeepestEnterEventTarget &&
482 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
483 aOriginalOverTargetInComposedDoc, mDeepestEnterEventTarget))) {
484 StoreOverEventTargetAndDeepestEnterEventTarget(
485 aOriginalOverTargetInComposedDoc);
486 LogModule* const logModule = mType == BoundaryEventType::Mouse
487 ? sMouseBoundaryLog
488 : sPointerBoundaryLog;
489 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
490 ("The \"over\" event target (%p) is restored",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
491 mDeepestEnterEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
;
492 }
493}
494
495void OverOutElementsWrapper::StoreOverEventTargetAndDeepestEnterEventTarget(
496 nsIContent* aOverEventTargetAndDeepestEnterEventTarget) {
497 mDeepestEnterEventTarget = aOverEventTargetAndDeepestEnterEventTarget;
498 mPendingRemovingOverEventTarget = nullptr;
499 mDeepestEnterEventTargetIsOverEventTarget = !!mDeepestEnterEventTarget;
500 mLastOverWidget = nullptr; // Set it after dispatching the "over" event.
501}
502
503void OverOutElementsWrapper::UpdateDeepestEnterEventTarget(
504 nsIContent* aDeepestEnterEventTarget) {
505 if (MOZ_UNLIKELY(mDeepestEnterEventTarget == aDeepestEnterEventTarget)(__builtin_expect(!!(mDeepestEnterEventTarget == aDeepestEnterEventTarget
), 0))
) {
506 return;
507 }
508
509 if (!aDeepestEnterEventTarget) {
510 // If the root element is removed, we don't need to dispatch "leave"
511 // events on any elements. Therefore, we can forget everything.
512 StoreOverEventTargetAndDeepestEnterEventTarget(nullptr);
513 return;
514 }
515
516 if (LastOverEventTargetIsOutEventTarget()) {
517 MOZ_ASSERT(mDeepestEnterEventTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDeepestEnterEventTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("mDeepestEnterEventTarget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 517); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget"
")"); do { *((volatile int*)__null) = 517; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
518 if (mType == BoundaryEventType::Pointer) {
519 // The spec of Pointer Events defines that once the `pointerover` event
520 // target is removed from the tree, `pointerout` should not be fired on
521 // that and the closest connected ancestor at the target removal should be
522 // kept as the deepest `pointerleave` target. All browsers considers the
523 // last `pointerover` event target is removed immediately when it occurs.
524 // Therefore, we don't need the special handling which we do for the
525 // `mouseout` event target below for considering whether we'll dispatch
526 // `pointerout` on the last `pointerover` target.
527 mPendingRemovingOverEventTarget = nullptr;
528 } else {
529 // Now, the `mouseout` event target is removed from the DOM at least
530 // temporarily. Let's keep storing it for restoring it if it's
531 // reconnected into mDeepestEnterEventTarget in a tick because the other
532 // browsers do not treat temporary removal of the last `mouseover` target
533 // keeps storing it as the next `mouseout` event target.
534 MOZ_ASSERT(!mPendingRemovingOverEventTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mPendingRemovingOverEventTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mPendingRemovingOverEventTarget
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!mPendingRemovingOverEventTarget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 534); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mPendingRemovingOverEventTarget"
")"); do { *((volatile int*)__null) = 534; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
535 MOZ_ASSERT(mDeepestEnterEventTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDeepestEnterEventTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("mDeepestEnterEventTarget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 535); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget"
")"); do { *((volatile int*)__null) = 535; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
536 mPendingRemovingOverEventTarget =
537 do_GetWeakReference(mDeepestEnterEventTarget);
538 }
539 } else {
540 MOZ_ASSERT(!mDeepestEnterEventTargetIsOverEventTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDeepestEnterEventTargetIsOverEventTarget)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!mDeepestEnterEventTargetIsOverEventTarget))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!mDeepestEnterEventTargetIsOverEventTarget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 540); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDeepestEnterEventTargetIsOverEventTarget"
")"); do { *((volatile int*)__null) = 540; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
541 // If mDeepestEnterEventTarget is not the last "over" event target, we've
542 // already done the complicated state managing above. Therefore, we only
543 // need to update mDeepestEnterEventTarget in this case.
544 }
545 mDeepestEnterEventTarget = aDeepestEnterEventTarget;
546 mDeepestEnterEventTargetIsOverEventTarget = false;
547 // Do not update mLastOverWidget here because it's required to ignore some
548 // following pointer events which are fired on widget under different top
549 // level widget.
550}
551
552/******************************************************************/
553/* mozilla::EventStateManager */
554/******************************************************************/
555
556static uint32_t sESMInstanceCount = 0;
557
558bool EventStateManager::sNormalLMouseEventInProcess = false;
559int16_t EventStateManager::sCurrentMouseBtn = MouseButton::eNotPressed;
560EventStateManager* EventStateManager::sActiveESM = nullptr;
561EventStateManager* EventStateManager::sCursorSettingManager = nullptr;
562AutoWeakFrame EventStateManager::sLastDragOverFrame = nullptr;
563LayoutDeviceIntPoint EventStateManager::sPreLockScreenPoint =
564 LayoutDeviceIntPoint(0, 0);
565LayoutDeviceIntPoint EventStateManager::sLastRefPoint = kInvalidRefPoint;
566CSSIntPoint EventStateManager::sLastScreenPoint = CSSIntPoint(0, 0);
567LayoutDeviceIntPoint EventStateManager::sSynthCenteringPoint = kInvalidRefPoint;
568CSSIntPoint EventStateManager::sLastClientPoint = CSSIntPoint(0, 0);
569nsCOMPtr<nsIContent> EventStateManager::sDragOverContent = nullptr;
570
571EventStateManager::WheelPrefs* EventStateManager::WheelPrefs::sInstance =
572 nullptr;
573EventStateManager::DeltaAccumulator*
574 EventStateManager::DeltaAccumulator::sInstance = nullptr;
575
576constexpr const StyleCursorKind kInvalidCursorKind =
577 static_cast<StyleCursorKind>(255);
578
579EventStateManager::EventStateManager()
580 : mLockCursor(kInvalidCursorKind),
581 mCurrentTarget(nullptr),
582 // init d&d gesture state machine variables
583 mGestureDownPoint(0, 0),
584 mGestureModifiers(0),
585 mGestureDownButtons(0),
586 mGestureDownButton(0),
587 mPresContext(nullptr),
588 mShouldAlwaysUseLineDeltas(false),
589 mShouldAlwaysUseLineDeltasInitialized(false),
590 mGestureDownInTextControl(false),
591 mInTouchDrag(false),
592 m_haveShutdown(false) {
593 if (sESMInstanceCount == 0) {
594 gUserInteractionTimerCallback = new UITimerCallback();
595 if (gUserInteractionTimerCallback) NS_ADDREF(gUserInteractionTimerCallback)(gUserInteractionTimerCallback)->AddRef();
596 UpdateUserActivityTimer();
597 }
598 ++sESMInstanceCount;
599}
600
601nsresult EventStateManager::UpdateUserActivityTimer() {
602 if (!gUserInteractionTimerCallback) return NS_OK;
603
604 if (!gUserInteractionTimer) {
605 gUserInteractionTimer = NS_NewTimer().take();
606 }
607
608 if (gUserInteractionTimer) {
609 gUserInteractionTimer->InitWithCallback(
610 gUserInteractionTimerCallback,
611 StaticPrefs::dom_events_user_interaction_interval(),
612 nsITimer::TYPE_ONE_SHOT);
613 }
614 return NS_OK;
615}
616
617nsresult EventStateManager::Init() {
618 nsCOMPtr<nsIObserverService> observerService =
619 mozilla::services::GetObserverService();
620 if (!observerService) return NS_ERROR_FAILURE;
621
622 observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown", true);
623
624 return NS_OK;
625}
626
627bool EventStateManager::ShouldAlwaysUseLineDeltas() {
628 if (MOZ_UNLIKELY(!mShouldAlwaysUseLineDeltasInitialized)(__builtin_expect(!!(!mShouldAlwaysUseLineDeltasInitialized),
0))
) {
629 mShouldAlwaysUseLineDeltasInitialized = true;
630 mShouldAlwaysUseLineDeltas =
631 !StaticPrefs::dom_event_wheel_deltaMode_lines_disabled();
632 if (!mShouldAlwaysUseLineDeltas && mDocument) {
633 if (nsIPrincipal* principal =
634 mDocument->GetPrincipalForPrefBasedHacks()) {
635 mShouldAlwaysUseLineDeltas = principal->IsURIInPrefList(
636 "dom.event.wheel-deltaMode-lines.always-enabled");
637 }
638 }
639 }
640 return mShouldAlwaysUseLineDeltas;
641}
642
643EventStateManager::~EventStateManager() {
644 ReleaseCurrentIMEContentObserver();
645
646 if (sActiveESM == this) {
647 sActiveESM = nullptr;
648 }
649
650 if (StaticPrefs::ui_click_hold_context_menus()) {
651 KillClickHoldTimer();
652 }
653
654 if (sCursorSettingManager == this) {
655 sCursorSettingManager = nullptr;
656 }
657
658 --sESMInstanceCount;
659 if (sESMInstanceCount == 0) {
660 WheelTransaction::Shutdown();
661 if (gUserInteractionTimerCallback) {
662 gUserInteractionTimerCallback->Notify(nullptr);
663 NS_RELEASE(gUserInteractionTimerCallback)do { (gUserInteractionTimerCallback)->Release(); (gUserInteractionTimerCallback
) = 0; } while (0)
;
664 }
665 if (gUserInteractionTimer) {
666 gUserInteractionTimer->Cancel();
667 NS_RELEASE(gUserInteractionTimer)do { (gUserInteractionTimer)->Release(); (gUserInteractionTimer
) = 0; } while (0)
;
668 }
669 WheelPrefs::Shutdown();
670 DeltaAccumulator::Shutdown();
671 }
672
673 if (sDragOverContent && sDragOverContent->OwnerDoc() == mDocument) {
674 sDragOverContent = nullptr;
675 }
676
677 if (!m_haveShutdown) {
678 Shutdown();
679
680 // Don't remove from Observer service in Shutdown because Shutdown also
681 // gets called from xpcom shutdown observer. And we don't want to remove
682 // from the service in that case.
683
684 nsCOMPtr<nsIObserverService> observerService =
685 mozilla::services::GetObserverService();
686 if (observerService) {
687 observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown");
688 }
689 }
690}
691
692nsresult EventStateManager::Shutdown() {
693 m_haveShutdown = true;
694 return NS_OK;
695}
696
697NS_IMETHODIMPnsresult
698EventStateManager::Observe(nsISupports* aSubject, const char* aTopic,
699 const char16_t* someData) {
700 if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown")) {
701 Shutdown();
702 }
703
704 return NS_OK;
705}
706
707NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(EventStateManager)nsresult EventStateManager::QueryInterface(const nsIID& aIID
, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 707); MOZ_PretendNoReturn(); } } while (0); nsISupports* foundInterface
; if (TopThreeWordsEquals( aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID), (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID)) && (LowWordEquals(aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID)) || LowWordEquals(aIID, (nsCycleCollectionISupports::COMTypeInfo
<nsCycleCollectionISupports, void>::kIID)))) { if (LowWordEquals
(aIID, (nsXPCOMCycleCollectionParticipant::COMTypeInfo<nsXPCOMCycleCollectionParticipant
, void>::kIID))) { *aInstancePtr = EventStateManager::cycleCollection
::GetParticipant(); return NS_OK; } if (LowWordEquals(aIID, (
nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID))) { *aInstancePtr = EventStateManager::cycleCollection
::Upcast(this); return NS_OK; } foundInterface = nullptr; } else
708 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupports>)) foundInterface = static_cast
<nsISupports*>(static_cast<nsIObserver*>(this)); else
709 NS_INTERFACE_MAP_ENTRY(nsIObserver)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIObserver>)) foundInterface = static_cast
<nsIObserver*>(this); else
710 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupportsWeakReference>)) foundInterface
= static_cast<nsISupportsWeakReference*>(this); else
711NS_INTERFACE_MAP_ENDfoundInterface = 0; nsresult status; if (!foundInterface) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(!aIID.Equals((nsISupports::COMTypeInfo<nsISupports
, void>::kIID)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aIID.Equals((nsISupports::COMTypeInfo
<nsISupports, void>::kIID))))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 711); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
")"); do { *((volatile int*)__null) = 711; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); status = NS_NOINTERFACE
; } else { (foundInterface)->AddRef(); status = NS_OK; } *
aInstancePtr = foundInterface; return status; }
712
713NS_IMPL_CYCLE_COLLECTING_ADDREF(EventStateManager)MozExternalRefCountType EventStateManager::AddRef(void) { static_assert
(!std::is_destructible_v<EventStateManager>, "Reference-counted class "
"EventStateManager" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 713); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
713; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); _mOwningThread.AssertOwnership("EventStateManager"
" not thread-safe"); nsISupports* base = EventStateManager::
cycleCollection::Upcast(this); nsrefcnt count = mRefCnt.incr(
base); NS_LogAddRef((this), (count), ("EventStateManager"), (
uint32_t)(sizeof(*this))); return count; }
714NS_IMPL_CYCLE_COLLECTING_RELEASE(EventStateManager)MozExternalRefCountType EventStateManager::Release(void) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 714); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 714
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); _mOwningThread.AssertOwnership("EventStateManager" " not thread-safe"
); nsISupports* base = EventStateManager::cycleCollection::Upcast
(this); nsrefcnt count = mRefCnt.decr(base); NS_LogRelease((this
), (count), ("EventStateManager")); return count; } void EventStateManager
::DeleteCycleCollectable(void) { delete (this); }
715
716NS_IMPL_CYCLE_COLLECTION_WEAK(EventStateManager, mCurrentTargetContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
717 mGestureDownContent, mGestureDownFrameOwner,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
718 mLastLeftMouseDownInfo.mLastMouseDownContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
719 mLastMiddleMouseDownInfo.mLastMouseDownContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
720 mLastRightMouseDownInfo.mLastMouseDownContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
721 mActiveContent, mHoverContent, mURLTargetContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
722 mPopoverPointerDownTarget, mMouseEnterLeaveHelper,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
723 mPointersEnterLeaveHelper, mDocument,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
724 mIMEContentObserver, mAccessKeys)EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
725
726void EventStateManager::ReleaseCurrentIMEContentObserver() {
727 if (mIMEContentObserver) {
728 mIMEContentObserver->DisconnectFromEventStateManager();
729 }
730 mIMEContentObserver = nullptr;
731}
732
733void EventStateManager::OnStartToObserveContent(
734 IMEContentObserver* aIMEContentObserver) {
735 if (mIMEContentObserver == aIMEContentObserver) {
736 return;
737 }
738 ReleaseCurrentIMEContentObserver();
739 mIMEContentObserver = aIMEContentObserver;
740}
741
742void EventStateManager::OnStopObservingContent(
743 IMEContentObserver* aIMEContentObserver) {
744 aIMEContentObserver->DisconnectFromEventStateManager();
745 NS_ENSURE_TRUE_VOID(mIMEContentObserver == aIMEContentObserver)do { if ((__builtin_expect(!!(!(mIMEContentObserver == aIMEContentObserver
)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mIMEContentObserver == aIMEContentObserver"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 745); return; } } while (false)
;
746 mIMEContentObserver = nullptr;
747}
748
749void EventStateManager::TryToFlushPendingNotificationsToIME() {
750 if (mIMEContentObserver) {
751 mIMEContentObserver->TryToFlushPendingNotifications(true);
752 }
753}
754
755static bool IsMessageMouseUserActivity(EventMessage aMessage) {
756 return aMessage == eMouseMove || aMessage == eMouseUp ||
757 aMessage == eMouseDown || aMessage == ePointerAuxClick ||
758 aMessage == eMouseDoubleClick || aMessage == ePointerClick ||
759 aMessage == eMouseActivate || aMessage == eMouseLongTap;
760}
761
762static bool IsMessageGamepadUserActivity(EventMessage aMessage) {
763 return aMessage == eGamepadButtonDown || aMessage == eGamepadButtonUp ||
764 aMessage == eGamepadAxisMove;
765}
766
767// static
768bool EventStateManager::IsKeyboardEventUserActivity(WidgetEvent* aEvent) {
769 // We ignore things that shouldn't cause popups, but also things that look
770 // like shortcut presses. In some obscure cases these may actually be
771 // website input, but any meaningful website will have other input anyway,
772 // and we can't very well tell whether shortcut input was supposed to be
773 // directed at chrome or the document.
774
775 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
776 // Access keys should be treated as page interaction.
777 if (keyEvent->ModifiersMatchWithAccessKey(AccessKeyType::eContent)) {
778 return true;
779 }
780 if (!keyEvent->CanTreatAsUserInput() || keyEvent->IsControl() ||
781 keyEvent->IsMeta() || keyEvent->IsAlt()) {
782 return false;
783 }
784 // Deal with function keys:
785 switch (keyEvent->mKeyNameIndex) {
786 case KEY_NAME_INDEX_F1:
787 case KEY_NAME_INDEX_F2:
788 case KEY_NAME_INDEX_F3:
789 case KEY_NAME_INDEX_F4:
790 case KEY_NAME_INDEX_F5:
791 case KEY_NAME_INDEX_F6:
792 case KEY_NAME_INDEX_F7:
793 case KEY_NAME_INDEX_F8:
794 case KEY_NAME_INDEX_F9:
795 case KEY_NAME_INDEX_F10:
796 case KEY_NAME_INDEX_F11:
797 case KEY_NAME_INDEX_F12:
798 case KEY_NAME_INDEX_F13:
799 case KEY_NAME_INDEX_F14:
800 case KEY_NAME_INDEX_F15:
801 case KEY_NAME_INDEX_F16:
802 case KEY_NAME_INDEX_F17:
803 case KEY_NAME_INDEX_F18:
804 case KEY_NAME_INDEX_F19:
805 case KEY_NAME_INDEX_F20:
806 case KEY_NAME_INDEX_F21:
807 case KEY_NAME_INDEX_F22:
808 case KEY_NAME_INDEX_F23:
809 case KEY_NAME_INDEX_F24:
810 return false;
811 default:
812 return true;
813 }
814}
815
816static void OnTypingInteractionEnded() {
817 // We don't consider a single keystroke to be typing.
818 if (gTypingInteractionKeyPresses > 1) {
819 gTypingInteraction.mInteractionCount += gTypingInteractionKeyPresses;
820 gTypingInteraction.mInteractionTimeInMilliseconds += static_cast<uint32_t>(
821 std::ceil((gTypingEndTime - gTypingStartTime).ToMilliseconds()));
822 }
823
824 gTypingInteractionKeyPresses = 0;
825 gTypingStartTime = TimeStamp();
826 gTypingEndTime = TimeStamp();
827}
828
829static void HandleKeyUpInteraction(WidgetKeyboardEvent* aKeyEvent) {
830 if (EventStateManager::IsKeyboardEventUserActivity(aKeyEvent)) {
831 TimeStamp now = TimeStamp::Now();
832 if (gTypingEndTime.IsNull()) {
833 gTypingEndTime = now;
834 }
835 TimeDuration delay = now - gTypingEndTime;
836 // Has it been too long since the last keystroke to be considered typing?
837 if (gTypingInteractionKeyPresses > 0 &&
838 delay >
839 TimeDuration::FromMilliseconds(
840 StaticPrefs::browser_places_interactions_typing_timeout_ms())) {
841 OnTypingInteractionEnded();
842 }
843 gTypingInteractionKeyPresses++;
844 if (gTypingStartTime.IsNull()) {
845 gTypingStartTime = now;
846 }
847 gTypingEndTime = now;
848 }
849}
850
851nsresult EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
852 WidgetEvent* aEvent,
853 nsIFrame* aTargetFrame,
854 nsIContent* aTargetContent,
855 nsEventStatus* aStatus,
856 nsIContent* aOverrideClickTarget) {
857 AUTO_PROFILER_LABEL("EventStateManager::PreHandleEvent", DOM)mozilla::AutoProfilerLabel raiiObject857( "EventStateManager::PreHandleEvent"
, nullptr, JS::ProfilingCategoryPair::DOM)
;
858 NS_ENSURE_ARG_POINTER(aStatus)do { if ((__builtin_expect(!!(!(aStatus)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStatus" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 858); return NS_ERROR_INVALID_POINTER; } } while (false)
;
859 NS_ENSURE_ARG(aPresContext)do { if ((__builtin_expect(!!(!(aPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 859); return NS_ERROR_INVALID_ARG; } } while (false)
;
860 if (!aEvent) {
861 NS_ERROR("aEvent is null. This should never happen.")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "aEvent is null. This should never happen."
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 861); MOZ_PretendNoReturn(); } while (0)
;
862 return NS_ERROR_NULL_POINTER;
863 }
864
865 NS_WARNING_ASSERTION(do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
866 !aTargetFrame || !aTargetFrame->GetContent() ||do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
867 aTargetFrame->GetContent() == aTargetContent ||do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
868 aTargetFrame->GetContent()->GetFlattenedTreeParent() ==do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
869 aTargetContent ||do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
870 aTargetFrame->IsGeneratedContentFrame(),do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
871 "aTargetFrame should be related with aTargetContent")do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
;
872#if DEBUG1
873 if (aTargetFrame && aTargetFrame->IsGeneratedContentFrame()) {
874 nsCOMPtr<nsIContent> targetContent;
875 aTargetFrame->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
876 MOZ_ASSERT(aTargetContent == targetContent,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTargetContent == targetContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTargetContent == targetContent
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aTargetContent == targetContent" " (" "Unexpected target for generated content frame!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTargetContent == targetContent"
") (" "Unexpected target for generated content frame!" ")");
do { *((volatile int*)__null) = 877; __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
877 "Unexpected target for generated content frame!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTargetContent == targetContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTargetContent == targetContent
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aTargetContent == targetContent" " (" "Unexpected target for generated content frame!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTargetContent == targetContent"
") (" "Unexpected target for generated content frame!" ")");
do { *((volatile int*)__null) = 877; __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
878 }
879#endif
880
881 mCurrentTarget = aTargetFrame;
882 mCurrentTargetContent = nullptr;
883
884 // Do not take account eMouseEnterIntoWidget/ExitFromWidget so that loading
885 // a page when user is not active doesn't change the state to active.
886 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
887 if (aEvent->IsTrusted() &&
888 ((mouseEvent && mouseEvent->IsReal() &&
889 IsMessageMouseUserActivity(mouseEvent->mMessage)) ||
890 aEvent->mClass == eWheelEventClass ||
891 aEvent->mClass == ePointerEventClass ||
892 aEvent->mClass == eTouchEventClass ||
893 aEvent->mClass == eKeyboardEventClass ||
894 (aEvent->mClass == eDragEventClass && aEvent->mMessage == eDrop) ||
895 IsMessageGamepadUserActivity(aEvent->mMessage))) {
896 if (gMouseOrKeyboardEventCounter == 0) {
897 nsCOMPtr<nsIObserverService> obs =
898 mozilla::services::GetObserverService();
899 if (obs) {
900 obs->NotifyObservers(nullptr, "user-interaction-active", nullptr);
901 UpdateUserActivityTimer();
902 }
903 }
904 ++gMouseOrKeyboardEventCounter;
905
906 nsCOMPtr<nsINode> node = aTargetContent;
907 if (node &&
908 ((aEvent->mMessage == eKeyUp && IsKeyboardEventUserActivity(aEvent)) ||
909 aEvent->mMessage == eMouseUp || aEvent->mMessage == eWheel ||
910 aEvent->mMessage == eTouchEnd || aEvent->mMessage == ePointerUp ||
911 aEvent->mMessage == eDrop)) {
912 Document* doc = node->OwnerDoc();
913 while (doc) {
914 doc->SetUserHasInteracted();
915 doc = nsContentUtils::IsChildOfSameType(doc)
916 ? doc->GetInProcessParentDocument()
917 : nullptr;
918 }
919 }
920 }
921
922 WheelTransaction::OnEvent(aEvent);
923
924 // Focus events don't necessarily need a frame.
925 if (!mCurrentTarget && !aTargetContent) {
926 NS_ERROR("mCurrentTarget and aTargetContent are null")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "mCurrentTarget and aTargetContent are null"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 926); MOZ_PretendNoReturn(); } while (0)
;
927 return NS_ERROR_NULL_POINTER;
928 }
929#ifdef DEBUG1
930 if (aEvent->HasDragEventMessage() && PointerLockManager::IsLocked()) {
931 NS_ASSERTION(PointerLockManager::IsLocked(),do { if (!(PointerLockManager::IsLocked())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Pointer is locked. Drag events should be suppressed when "
"the pointer is locked.", "PointerLockManager::IsLocked()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 933); MOZ_PretendNoReturn(); } } while (0)
932 "Pointer is locked. Drag events should be suppressed when "do { if (!(PointerLockManager::IsLocked())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Pointer is locked. Drag events should be suppressed when "
"the pointer is locked.", "PointerLockManager::IsLocked()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 933); MOZ_PretendNoReturn(); } } while (0)
933 "the pointer is locked.")do { if (!(PointerLockManager::IsLocked())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Pointer is locked. Drag events should be suppressed when "
"the pointer is locked.", "PointerLockManager::IsLocked()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 933); MOZ_PretendNoReturn(); } } while (0)
;
934 }
935#endif
936 // Store last known screenPoint and clientPoint so pointer lock
937 // can use these values as constants.
938 if (aEvent->IsTrusted() &&
939 ((mouseEvent && mouseEvent->IsReal()) ||
940 aEvent->mClass == eWheelEventClass) &&
941 !PointerLockManager::IsLocked()) {
942 // XXX Probably doesn't matter much, but storing these in CSS pixels instead
943 // of device pixels means behavior can be a bit odd if you zoom while
944 // pointer-locked.
945 sLastScreenPoint =
946 Event::GetScreenCoords(aPresContext, aEvent, aEvent->mRefPoint)
947 .extract();
948 sLastClientPoint = Event::GetClientCoords(
949 aPresContext, aEvent, aEvent->mRefPoint, CSSIntPoint(0, 0));
950 }
951
952 *aStatus = nsEventStatus_eIgnore;
953
954 if (aEvent->mClass == eQueryContentEventClass) {
955 HandleQueryContentEvent(aEvent->AsQueryContentEvent());
956 return NS_OK;
957 }
958
959 WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
960 if (touchEvent && mInTouchDrag) {
961 if (touchEvent->mMessage == eTouchMove) {
962 GenerateDragGesture(aPresContext, touchEvent);
963 } else {
964 mInTouchDrag = false;
965 StopTrackingDragGesture(true);
966 }
967 }
968
969 if (mMouseEnterLeaveHelper && aEvent->IsTrusted()) {
970 // When the last `mouseover` event target is removed from the document,
971 // we makes mMouseEnterLeaveHelper update the last deepest `mouseenter`
972 // event target to the removed node parent and mark it as not the following
973 // `mouseout` event target. However, the other browsers may dispatch
974 // `mouseout` on it if it's restored "immediately". Therefore, we use
975 // the next animation frame as the deadline. ContentRemoved() enqueues a
976 // synthesized `mousemove` to dispatch mouse boundary events under the
977 // mouse cursor soon and the synthesized event (or eMouseExitFromWidget if
978 // our window is moved) will reach here at latest the next animation frame.
979 // Therefore, we can use the event as the deadline. If the removed last
980 // `mouseover` target is reconnected before a synthesized mouse event or
981 // a real mouse event, let's restore it as the following `mouseout` event
982 // target. Otherwise, e.g., a keyboard event, let's forget it.
983 mMouseEnterLeaveHelper->TryToRestorePendingRemovedOverTarget(aEvent);
984 }
985
986 static constexpr auto const allowSynthesisForTests = []() -> bool {
987 nsCOMPtr<nsIDragService> dragService =
988 do_GetService("@mozilla.org/widget/dragservice;1");
989 return dragService &&
990 !dragService->GetNeverAllowSessionIsSynthesizedForTests();
991 };
992
993 switch (aEvent->mMessage) {
994 case eContextMenu:
995 if (PointerLockManager::IsLocked()) {
996 return NS_ERROR_DOM_INVALID_STATE_ERR;
997 }
998 break;
999 case eMouseTouchDrag:
1000 mInTouchDrag = true;
1001 BeginTrackingDragGesture(aPresContext, mouseEvent, aTargetFrame);
1002 break;
1003 case eMouseDown: {
1004 switch (mouseEvent->mButton) {
1005 case MouseButton::ePrimary:
1006 BeginTrackingDragGesture(aPresContext, mouseEvent, aTargetFrame);
1007 mLastLeftMouseDownInfo.mClickCount = mouseEvent->mClickCount;
1008 SetClickCount(mouseEvent, aStatus);
1009 sNormalLMouseEventInProcess = true;
1010 break;
1011 case MouseButton::eMiddle:
1012 mLastMiddleMouseDownInfo.mClickCount = mouseEvent->mClickCount;
1013 SetClickCount(mouseEvent, aStatus);
1014 break;
1015 case MouseButton::eSecondary:
1016 mLastRightMouseDownInfo.mClickCount = mouseEvent->mClickCount;
1017 SetClickCount(mouseEvent, aStatus);
1018 break;
1019 }
1020 if (!StaticPrefs::dom_popup_experimental()) {
1021 NotifyTargetUserActivation(aEvent, aTargetContent);
1022 }
1023 break;
1024 }
1025 case eMouseUp: {
1026 switch (mouseEvent->mButton) {
1027 case MouseButton::ePrimary:
1028 if (StaticPrefs::ui_click_hold_context_menus()) {
1029 KillClickHoldTimer();
1030 }
1031 mInTouchDrag = false;
1032 StopTrackingDragGesture(true);
1033 sNormalLMouseEventInProcess = false;
1034 // then fall through...
1035 [[fallthrough]];
1036 case MouseButton::eSecondary:
1037 case MouseButton::eMiddle:
1038 RefPtr<EventStateManager> esm =
1039 ESMFromContentOrThis(aOverrideClickTarget);
1040 esm->SetClickCount(mouseEvent, aStatus, aOverrideClickTarget);
1041 break;
1042 }
1043 break;
1044 }
1045 case eMouseEnterIntoWidget:
1046 PointerEventHandler::UpdateActivePointerState(mouseEvent, aTargetContent);
1047 // In some cases on e10s eMouseEnterIntoWidget
1048 // event was sent twice into child process of content.
1049 // (From specific widget code (sending is not permanent) and
1050 // from ESM::DispatchMouseOrPointerBoundaryEvent (sending is permanent)).
1051 // IsCrossProcessForwardingStopped() helps to suppress sending accidental
1052 // event from widget code.
1053 aEvent->StopCrossProcessForwarding();
1054 break;
1055 case eMouseExitFromWidget:
1056 // If this is a remote frame, we receive eMouseExitFromWidget from the
1057 // parent the mouse exits our content. Since the parent may update the
1058 // cursor while the mouse is outside our frame, and since PuppetWidget
1059 // caches the current cursor internally, re-entering our content (say from
1060 // over a window edge) wont update the cursor if the cached value and the
1061 // current cursor match. So when the mouse exits a remote frame, clear the
1062 // cached widget cursor so a proper update will occur when the mouse
1063 // re-enters.
1064 if (XRE_IsContentProcess()) {
1065 ClearCachedWidgetCursor(mCurrentTarget);
1066 }
1067
1068 // IsCrossProcessForwardingStopped() helps to suppress double event
1069 // sending into process of content. For more information see comment
1070 // above, at eMouseEnterIntoWidget case.
1071 aEvent->StopCrossProcessForwarding();
1072
1073 // If the event is not a top-level window or puppet widget exit, then it's
1074 // not really an exit --- we may have traversed widget boundaries but
1075 // we're still in our toplevel window or puppet widget.
1076 if (mouseEvent->mExitFrom.value() !=
1077 WidgetMouseEvent::ePlatformTopLevel &&
1078 mouseEvent->mExitFrom.value() != WidgetMouseEvent::ePuppet) {
1079 // Treat it as a synthetic move so we don't generate spurious
1080 // "exit" or "move" events. Any necessary "out" or "over" events
1081 // will be generated by GenerateMouseEnterExit
1082 mouseEvent->mMessage = eMouseMove;
1083 mouseEvent->mReason = WidgetMouseEvent::eSynthesized;
1084 // then fall through...
1085 } else {
1086 MOZ_ASSERT_IF(XRE_IsParentProcess(),do { if (XRE_IsParentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePlatformTopLevel)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1088); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
")"); do { *((volatile int*)__null) = 1088; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1087 mouseEvent->mExitFrom.value() ==do { if (XRE_IsParentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePlatformTopLevel)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1088); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
")"); do { *((volatile int*)__null) = 1088; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1088 WidgetMouseEvent::ePlatformTopLevel)do { if (XRE_IsParentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePlatformTopLevel)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1088); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
")"); do { *((volatile int*)__null) = 1088; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1089 MOZ_ASSERT_IF(XRE_IsContentProcess(), mouseEvent->mExitFrom.value() ==do { if (XRE_IsContentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePuppet)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mouseEvent->mExitFrom.value
() == WidgetMouseEvent::ePuppet))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1090); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
")"); do { *((volatile int*)__null) = 1090; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1090 WidgetMouseEvent::ePuppet)do { if (XRE_IsContentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePuppet)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mouseEvent->mExitFrom.value
() == WidgetMouseEvent::ePuppet))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1090); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
")"); do { *((volatile int*)__null) = 1090; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1091 // We should synthetize corresponding pointer events
1092 GeneratePointerEnterExit(ePointerLeave, mouseEvent);
1093 GenerateMouseEnterExit(mouseEvent);
1094 // This is really an exit and should stop here
1095 aEvent->mMessage = eVoidEvent;
1096 break;
1097 }
1098 [[fallthrough]];
1099 case eMouseMove:
1100 case ePointerDown:
1101 if (aEvent->mMessage == ePointerDown) {
1102 PointerEventHandler::UpdateActivePointerState(mouseEvent,
1103 aTargetContent);
1104 PointerEventHandler::ImplicitlyCapturePointer(aTargetFrame, aEvent);
1105 if (StaticPrefs::dom_popup_experimental()) {
1106 // https://html.spec.whatwg.org/multipage/interaction.html#activation-triggering-input-event
1107 if (mouseEvent->mInputSource ==
1108 MouseEvent_Binding::MOZ_SOURCE_MOUSE) {
1109 NotifyTargetUserActivation(aEvent, aTargetContent);
1110 }
1111 } else if (mouseEvent->mInputSource !=
1112 MouseEvent_Binding::MOZ_SOURCE_TOUCH) {
1113 NotifyTargetUserActivation(aEvent, aTargetContent);
1114 }
1115
1116 LightDismissOpenPopovers(aEvent, aTargetContent);
1117 }
1118 [[fallthrough]];
1119 case ePointerMove: {
1120 if (!mInTouchDrag &&
1121 PointerEventHandler::IsDragAndDropEnabled(*mouseEvent)) {
1122 GenerateDragGesture(aPresContext, mouseEvent);
1123 }
1124 // on the Mac, GenerateDragGesture() may not return until the drag
1125 // has completed and so |aTargetFrame| may have been deleted (moving
1126 // a bookmark, for example). If this is the case, however, we know
1127 // that ClearFrameRefs() has been called and it cleared out
1128 // |mCurrentTarget|. As a result, we should pass |mCurrentTarget|
1129 // into UpdateCursor().
1130 UpdateCursor(aPresContext, mouseEvent, mCurrentTarget, aStatus);
1131
1132 UpdateLastRefPointOfMouseEvent(mouseEvent);
1133 if (PointerLockManager::IsLocked()) {
1134 ResetPointerToWindowCenterWhilePointerLocked(mouseEvent);
1135 }
1136 UpdateLastPointerPosition(mouseEvent);
1137
1138 GenerateMouseEnterExit(mouseEvent);
1139 // Flush pending layout changes, so that later mouse move events
1140 // will go to the right nodes.
1141 FlushLayout(aPresContext);
1142 break;
1143 }
1144 case ePointerUp:
1145 LightDismissOpenPopovers(aEvent, aTargetContent);
1146 GenerateMouseEnterExit(mouseEvent);
1147 if (StaticPrefs::dom_popup_experimental() &&
1148 mouseEvent->mInputSource != MouseEvent_Binding::MOZ_SOURCE_MOUSE) {
1149 NotifyTargetUserActivation(aEvent, aTargetContent);
1150 }
1151 break;
1152 case ePointerGotCapture:
1153 GenerateMouseEnterExit(mouseEvent);
1154 break;
1155 case eDragStart:
1156 if (StaticPrefs::ui_click_hold_context_menus()) {
1157 // an external drag gesture event came in, not generated internally
1158 // by Gecko. Make sure we get rid of the click-hold timer.
1159 KillClickHoldTimer();
1160 }
1161 break;
1162 case eDragOver: {
1163 WidgetDragEvent* dragEvent = aEvent->AsDragEvent();
1164 MOZ_ASSERT(dragEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(dragEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(dragEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("dragEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1164); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dragEvent" ")"
); do { *((volatile int*)__null) = 1164; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1165 if (dragEvent->mFlags.mIsSynthesizedForTests &&
1166 allowSynthesisForTests()) {
1167 dragEvent->InitDropEffectForTests();
1168 }
1169 // Send the enter/exit events before eDrop.
1170 GenerateDragDropEnterExit(aPresContext, dragEvent);
1171 break;
1172 }
1173 case eDrop: {
1174 if (aEvent->mFlags.mIsSynthesizedForTests && allowSynthesisForTests()) {
1175 MOZ_ASSERT(aEvent->AsDragEvent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->AsDragEvent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->AsDragEvent()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->AsDragEvent()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1175); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->AsDragEvent()"
")"); do { *((volatile int*)__null) = 1175; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1176 aEvent->AsDragEvent()->InitDropEffectForTests();
1177 }
1178 break;
1179 }
1180 case eKeyPress: {
1181 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
1182 if (keyEvent->ModifiersMatchWithAccessKey(AccessKeyType::eChrome) ||
1183 keyEvent->ModifiersMatchWithAccessKey(AccessKeyType::eContent)) {
1184 // If the eKeyPress event will be sent to a remote process, this
1185 // process needs to wait reply from the remote process for checking if
1186 // preceding eKeyDown event is consumed. If preceding eKeyDown event
1187 // is consumed in the remote process, BrowserChild won't send the event
1188 // back to this process. So, only when this process receives a reply
1189 // eKeyPress event in BrowserParent, we should handle accesskey in this
1190 // process.
1191 if (IsTopLevelRemoteTarget(GetFocusedElement())) {
1192 // However, if there is no accesskey target for the key combination,
1193 // we don't need to wait reply from the remote process. Otherwise,
1194 // Mark the event as waiting reply from remote process and stop
1195 // propagation in this process.
1196 if (CheckIfEventMatchesAccessKey(keyEvent, aPresContext)) {
1197 keyEvent->StopPropagation();
1198 keyEvent->MarkAsWaitingReplyFromRemoteProcess();
1199 }
1200 }
1201 // If the event target is in this process, we can handle accesskey now
1202 // since if preceding eKeyDown event was consumed, eKeyPress event
1203 // won't be dispatched by widget. So, coming eKeyPress event means
1204 // that the preceding eKeyDown event wasn't consumed in this case.
1205 else {
1206 AutoTArray<uint32_t, 10> accessCharCodes;
1207 keyEvent->GetAccessKeyCandidates(accessCharCodes);
1208
1209 if (HandleAccessKey(keyEvent, aPresContext, accessCharCodes)) {
1210 *aStatus = nsEventStatus_eConsumeNoDefault;
1211 }
1212 }
1213 }
1214 }
1215 // then fall through...
1216 [[fallthrough]];
1217 case eKeyDown:
1218 if (aEvent->mMessage == eKeyDown) {
1219 NotifyTargetUserActivation(aEvent, aTargetContent);
1220 }
1221 [[fallthrough]];
1222 case eKeyUp: {
1223 Element* element = GetFocusedElement();
1224 if (element) {
1225 mCurrentTargetContent = element;
1226 }
1227
1228 // NOTE: Don't refer TextComposition::IsComposing() since UI Events
1229 // defines that KeyboardEvent.isComposing is true when it's
1230 // dispatched after compositionstart and compositionend.
1231 // TextComposition::IsComposing() is false even before
1232 // compositionend if there is no composing string.
1233 // And also don't expose other document's composition state.
1234 // A native IME context is typically shared by multiple documents.
1235 // So, don't use GetTextCompositionFor(nsIWidget*) here.
1236 RefPtr<TextComposition> composition =
1237 IMEStateManager::GetTextCompositionFor(aPresContext);
1238 aEvent->AsKeyboardEvent()->mIsComposing = !!composition;
1239
1240 // Widget may need to perform default action for specific keyboard
1241 // event if it's not consumed. In this case, widget has already marked
1242 // the event as "waiting reply from remote process". However, we need
1243 // to reset it if the target (focused content) isn't in a remote process
1244 // because PresShell needs to check if it's marked as so before
1245 // dispatching events into the DOM tree.
1246 if (aEvent->IsWaitingReplyFromRemoteProcess() &&
1247 !aEvent->PropagationStopped() && !IsTopLevelRemoteTarget(element)) {
1248 aEvent->ResetWaitingReplyFromRemoteProcessState();
1249 }
1250 } break;
1251 case eWheel:
1252 case eWheelOperationStart:
1253 case eWheelOperationEnd: {
1254 NS_ASSERTION(aEvent->IsTrusted(),do { if (!(aEvent->IsTrusted())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Untrusted wheel event shouldn't be here", "aEvent->IsTrusted()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1255); MOZ_PretendNoReturn(); } } while (0)
1255 "Untrusted wheel event shouldn't be here")do { if (!(aEvent->IsTrusted())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Untrusted wheel event shouldn't be here", "aEvent->IsTrusted()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1255); MOZ_PretendNoReturn(); } } while (0)
;
1256 using DeltaModeCheckingState = WidgetWheelEvent::DeltaModeCheckingState;
1257
1258 if (Element* element = GetFocusedElement()) {
1259 mCurrentTargetContent = element;
1260 }
1261
1262 if (aEvent->mMessage != eWheel) {
1263 break;
1264 }
1265
1266 WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
1267 WheelPrefs::GetInstance()->ApplyUserPrefsToDelta(wheelEvent);
1268
1269 // If we won't dispatch a DOM event for this event, nothing to do anymore.
1270 if (!wheelEvent->IsAllowedToDispatchDOMEvent()) {
1271 break;
1272 }
1273
1274 if (StaticPrefs::dom_event_wheel_deltaMode_lines_always_disabled()) {
1275 wheelEvent->mDeltaModeCheckingState = DeltaModeCheckingState::Unchecked;
1276 } else if (ShouldAlwaysUseLineDeltas()) {
1277 wheelEvent->mDeltaModeCheckingState = DeltaModeCheckingState::Checked;
1278 } else {
1279 wheelEvent->mDeltaModeCheckingState = DeltaModeCheckingState::Unknown;
1280 }
1281
1282 // Init lineOrPageDelta values for line scroll events for some devices
1283 // on some platforms which might dispatch wheel events which don't
1284 // have lineOrPageDelta values. And also, if delta values are
1285 // customized by prefs, this recomputes them.
1286 DeltaAccumulator::GetInstance()->InitLineOrPageDelta(aTargetFrame, this,
1287 wheelEvent);
1288 } break;
1289 case eSetSelection: {
1290 RefPtr<Element> focuedElement = GetFocusedElement();
1291 IMEStateManager::HandleSelectionEvent(aPresContext, focuedElement,
1292 aEvent->AsSelectionEvent());
1293 break;
1294 }
1295 case eContentCommandCut:
1296 case eContentCommandCopy:
1297 case eContentCommandPaste:
1298 case eContentCommandDelete:
1299 case eContentCommandUndo:
1300 case eContentCommandRedo:
1301 case eContentCommandPasteTransferable:
1302 case eContentCommandLookUpDictionary:
1303 DoContentCommandEvent(aEvent->AsContentCommandEvent());
1304 break;
1305 case eContentCommandInsertText:
1306 DoContentCommandInsertTextEvent(aEvent->AsContentCommandEvent());
1307 break;
1308 case eContentCommandReplaceText:
1309 DoContentCommandReplaceTextEvent(aEvent->AsContentCommandEvent());
1310 break;
1311 case eContentCommandScroll:
1312 DoContentCommandScrollEvent(aEvent->AsContentCommandEvent());
1313 break;
1314 case eCompositionStart:
1315 if (aEvent->IsTrusted()) {
1316 // If the event is trusted event, set the selected text to data of
1317 // composition event.
1318 WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent();
1319 WidgetQueryContentEvent querySelectedTextEvent(
1320 true, eQuerySelectedText, compositionEvent->mWidget);
1321 HandleQueryContentEvent(&querySelectedTextEvent);
1322 if (querySelectedTextEvent.FoundSelection()) {
1323 compositionEvent->mData = querySelectedTextEvent.mReply->DataRef();
1324 }
1325 NS_ASSERTION(querySelectedTextEvent.Succeeded(),do { if (!(querySelectedTextEvent.Succeeded())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Failed to get selected text", "querySelectedTextEvent.Succeeded()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1326); MOZ_PretendNoReturn(); } } while (0)
1326 "Failed to get selected text")do { if (!(querySelectedTextEvent.Succeeded())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Failed to get selected text", "querySelectedTextEvent.Succeeded()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1326); MOZ_PretendNoReturn(); } } while (0)
;
1327 }
1328 break;
1329 case eTouchStart:
1330 SetGestureDownPoint(aEvent->AsTouchEvent());
1331 break;
1332 case eTouchEnd:
1333 if (!StaticPrefs::dom_popup_experimental()) {
1334 NotifyTargetUserActivation(aEvent, aTargetContent);
1335 }
1336 break;
1337 default:
1338 break;
1339 }
1340 return NS_OK;
1341}
1342
1343// Returns true if this event is likely an user activation for a link or
1344// a link-like button, where modifier keys are likely be used for controlling
1345// where the link is opened.
1346//
1347// The modifiers associated with the user activation is used for controlling
1348// where the `window.open` is opened into.
1349static bool CanReflectModifiersToUserActivation(WidgetInputEvent* aEvent) {
1350 if (StaticPrefs::dom_popup_experimental()) {
1351 MOZ_ASSERT(aEvent->mMessage == eKeyDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1353); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1353; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1352 aEvent->mMessage == ePointerDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1353); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1353; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1353 aEvent->mMessage == ePointerUp)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1353); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1353; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1354 } else {
1355 MOZ_ASSERT(aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1357); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1357; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1356 aEvent->mMessage == ePointerDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1357); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1357; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1357 aEvent->mMessage == eTouchEnd)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1357); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1357; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1358 }
1359
1360 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
1361 if (keyEvent) {
1362 return keyEvent->CanReflectModifiersToUserActivation();
1363 }
1364
1365 return true;
1366}
1367
1368void EventStateManager::NotifyTargetUserActivation(WidgetEvent* aEvent,
1369 nsIContent* aTargetContent) {
1370 if (!aEvent->IsTrusted()) {
1371 return;
1372 }
1373
1374 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
1375 if (mouseEvent && !mouseEvent->IsReal()) {
1376 return;
1377 }
1378
1379 nsCOMPtr<nsINode> node = aTargetContent;
1380 if (!node) {
1381 return;
1382 }
1383
1384 Document* doc = node->OwnerDoc();
1385 if (!doc) {
1386 return;
1387 }
1388
1389 // Don't gesture activate for key events for keys which are likely
1390 // to be interaction with the browser, OS.
1391 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
1392 if (keyEvent && !keyEvent->CanUserGestureActivateTarget()) {
1393 return;
1394 }
1395
1396 // Touch gestures that end outside the drag target were touches that turned
1397 // into scroll/pan/swipe actions. We don't want to gesture activate on such
1398 // actions, we want to only gesture activate on touches that are taps.
1399 // That is, touches that end in roughly the same place that they started.
1400 if ((aEvent->mMessage == eTouchEnd ||
1401 (aEvent->mMessage == ePointerUp &&
1402 aEvent->AsPointerEvent()->mInputSource ==
1403 MouseEvent_Binding::MOZ_SOURCE_TOUCH)) &&
1404 IsEventOutsideDragThreshold(aEvent->AsInputEvent())) {
1405 return;
1406 }
1407
1408 // Do not treat the click on scrollbar as a user interaction with the web
1409 // content.
1410 if (StaticPrefs::dom_user_activation_ignore_scrollbars() &&
1411 ((StaticPrefs::dom_popup_experimental() &&
1412 (aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp)) ||
1413 (!StaticPrefs::dom_popup_experimental() &&
1414 (aEvent->mMessage == eMouseDown ||
1415 aEvent->mMessage == ePointerDown))) &&
1416 aTargetContent->IsInNativeAnonymousSubtree()) {
1417 nsIContent* current = aTargetContent;
1418 do {
1419 nsIContent* root = current->GetClosestNativeAnonymousSubtreeRoot();
1420 if (!root) {
1421 break;
1422 }
1423 if (root->IsXULElement(nsGkAtoms::scrollbar)) {
1424 return;
1425 }
1426 current = root->GetParent();
1427 } while (current);
1428 }
1429
1430#ifdef DEBUG1
1431 if (StaticPrefs::dom_popup_experimental()) {
1432 MOZ_ASSERT(aEvent->mMessage == eKeyDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1434); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1434; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1433 aEvent->mMessage == ePointerDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1434); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1434; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1434 aEvent->mMessage == ePointerUp)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1434); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1434; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1435 } else {
1436 MOZ_ASSERT(aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1438); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1438; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1437 aEvent->mMessage == ePointerDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1438); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1438; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1438 aEvent->mMessage == eTouchEnd)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1438); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1438; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1439 }
1440#endif
1441
1442 UserActivation::Modifiers modifiers;
1443 if (WidgetInputEvent* inputEvent = aEvent->AsInputEvent()) {
1444 if (CanReflectModifiersToUserActivation(inputEvent)) {
1445 if (inputEvent->IsShift()) {
1446 modifiers.SetShift();
1447 }
1448 if (inputEvent->IsMeta()) {
1449 modifiers.SetMeta();
1450 }
1451 if (inputEvent->IsControl()) {
1452 modifiers.SetControl();
1453 }
1454 if (inputEvent->IsAlt()) {
1455 modifiers.SetAlt();
1456 }
1457
1458 WidgetMouseEvent* mouseEvent = inputEvent->AsMouseEvent();
1459 if (mouseEvent) {
1460 if (mouseEvent->mButton == MouseButton::eMiddle) {
1461 modifiers.SetMiddleMouse();
1462 }
1463 }
1464 }
1465 }
1466 doc->NotifyUserGestureActivation(modifiers);
1467}
1468
1469// https://html.spec.whatwg.org/multipage/popover.html#popover-light-dismiss
1470void EventStateManager::LightDismissOpenPopovers(WidgetEvent* aEvent,
1471 nsIContent* aTargetContent) {
1472 MOZ_ASSERT(aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == ePointerDown || aEvent->mMessage
== ePointerUp)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
" (" "Light dismiss must be called for pointer up/down only"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
") (" "Light dismiss must be called for pointer up/down only"
")"); do { *((volatile int*)__null) = 1473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1473 "Light dismiss must be called for pointer up/down only")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == ePointerDown || aEvent->mMessage
== ePointerUp)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
" (" "Light dismiss must be called for pointer up/down only"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
") (" "Light dismiss must be called for pointer up/down only"
")"); do { *((volatile int*)__null) = 1473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1474
1475 if (!StaticPrefs::dom_element_popover_enabled() || !aEvent->IsTrusted() ||
1476 !aTargetContent) {
1477 return;
1478 }
1479
1480 Element* topmostPopover = aTargetContent->OwnerDoc()->GetTopmostAutoPopover();
1481 if (!topmostPopover) {
1482 return;
1483 }
1484
1485 // Pointerdown: set document's popover pointerdown target to the result of
1486 // running topmost clicked popover given target.
1487 if (aEvent->mMessage == ePointerDown) {
1488 mPopoverPointerDownTarget = aTargetContent->GetTopmostClickedPopover();
1489 return;
1490 }
1491
1492 // Pointerup: hide open popovers.
1493 RefPtr<nsINode> ancestor = aTargetContent->GetTopmostClickedPopover();
1494 bool sameTarget = mPopoverPointerDownTarget == ancestor;
1495 mPopoverPointerDownTarget = nullptr;
1496 if (!sameTarget) {
1497 return;
1498 }
1499
1500 if (!ancestor) {
1501 ancestor = aTargetContent->OwnerDoc();
1502 }
1503 RefPtr<Document> doc(ancestor->OwnerDoc());
1504 doc->HideAllPopoversUntil(*ancestor, false, true);
1505}
1506
1507already_AddRefed<EventStateManager> EventStateManager::ESMFromContentOrThis(
1508 nsIContent* aContent) {
1509 if (aContent) {
1510 PresShell* presShell = aContent->OwnerDoc()->GetPresShell();
1511 if (presShell) {
1512 nsPresContext* prescontext = presShell->GetPresContext();
1513 if (prescontext) {
1514 RefPtr<EventStateManager> esm = prescontext->EventStateManager();
1515 if (esm) {
1516 return esm.forget();
1517 }
1518 }
1519 }
1520 }
1521
1522 RefPtr<EventStateManager> esm = this;
1523 return esm.forget();
1524}
1525
1526EventStateManager::LastMouseDownInfo& EventStateManager::GetLastMouseDownInfo(
1527 int16_t aButton) {
1528 switch (aButton) {
1529 case MouseButton::ePrimary:
1530 return mLastLeftMouseDownInfo;
1531 case MouseButton::eMiddle:
1532 return mLastMiddleMouseDownInfo;
1533 case MouseButton::eSecondary:
1534 return mLastRightMouseDownInfo;
1535 default:
1536 MOZ_ASSERT_UNREACHABLE("This button shouldn't use this method")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"This button shouldn't use this method" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1536); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "This button shouldn't use this method"
")"); do { *((volatile int*)__null) = 1536; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1537 return mLastLeftMouseDownInfo;
1538 }
1539}
1540
1541void EventStateManager::HandleQueryContentEvent(
1542 WidgetQueryContentEvent* aEvent) {
1543 switch (aEvent->mMessage) {
1544 case eQuerySelectedText:
1545 case eQueryTextContent:
1546 case eQueryCaretRect:
1547 case eQueryTextRect:
1548 case eQueryEditorRect:
1549 if (!IsTargetCrossProcess(aEvent)) {
1550 break;
1551 }
1552 // Will not be handled locally, remote the event
1553 GetCrossProcessTarget()->HandleQueryContentEvent(*aEvent);
1554 return;
1555 // Following events have not been supported in e10s mode yet.
1556 case eQueryContentState:
1557 case eQuerySelectionAsTransferable:
1558 case eQueryCharacterAtPoint:
1559 case eQueryDOMWidgetHittest:
1560 case eQueryTextRectArray:
1561 case eQueryDropTargetHittest:
1562 break;
1563 default:
1564 return;
1565 }
1566
1567 // If there is an IMEContentObserver, we need to handle QueryContentEvent
1568 // with it.
1569 // eQueryDropTargetHittest is not really an IME event, though
1570 if (mIMEContentObserver && aEvent->mMessage != eQueryDropTargetHittest) {
1571 RefPtr<IMEContentObserver> contentObserver = mIMEContentObserver;
1572 contentObserver->HandleQueryContentEvent(aEvent);
1573 return;
1574 }
1575
1576 ContentEventHandler handler(mPresContext);
1577 handler.HandleQueryContentEvent(aEvent);
1578}
1579
1580static AccessKeyType GetAccessKeyTypeFor(nsISupports* aDocShell) {
1581 nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(aDocShell));
1582 if (!treeItem) {
1583 return AccessKeyType::eNone;
1584 }
1585
1586 switch (treeItem->ItemType()) {
1587 case nsIDocShellTreeItem::typeChrome:
1588 return AccessKeyType::eChrome;
1589 case nsIDocShellTreeItem::typeContent:
1590 return AccessKeyType::eContent;
1591 default:
1592 return AccessKeyType::eNone;
1593 }
1594}
1595
1596static bool IsAccessKeyTarget(Element* aElement, nsAString& aKey) {
1597 // Use GetAttr because we want Unicode case=insensitive matching
1598 // XXXbz shouldn't this be case-sensitive, per spec?
1599 nsString contentKey;
1600 if (!aElement || !aElement->GetAttr(nsGkAtoms::accesskey, contentKey) ||
1601 !contentKey.Equals(aKey, nsCaseInsensitiveStringComparator)) {
1602 return false;
1603 }
1604
1605 if (!aElement->IsXULElement()) {
1606 return true;
1607 }
1608
1609 // For XUL we do visibility checks.
1610 nsIFrame* frame = aElement->GetPrimaryFrame();
1611 if (!frame) {
1612 return false;
1613 }
1614
1615 if (frame->IsFocusable()) {
1616 return true;
1617 }
1618
1619 if (!frame->IsVisibleConsideringAncestors()) {
1620 return false;
1621 }
1622
1623 // XUL controls can be activated.
1624 nsCOMPtr<nsIDOMXULControlElement> control = aElement->AsXULControl();
1625 if (control) {
1626 return true;
1627 }
1628
1629 // XUL label elements are never focusable, so we need to check for them
1630 // explicitly before giving up.
1631 if (aElement->IsXULElement(nsGkAtoms::label)) {
1632 return true;
1633 }
1634
1635 return false;
1636}
1637
1638bool EventStateManager::CheckIfEventMatchesAccessKey(
1639 WidgetKeyboardEvent* aEvent, nsPresContext* aPresContext) {
1640 AutoTArray<uint32_t, 10> accessCharCodes;
1641 aEvent->GetAccessKeyCandidates(accessCharCodes);
1642 return WalkESMTreeToHandleAccessKey(aEvent, aPresContext, accessCharCodes,
1643 nullptr, eAccessKeyProcessingNormal,
1644 false);
1645}
1646
1647bool EventStateManager::LookForAccessKeyAndExecute(
1648 nsTArray<uint32_t>& aAccessCharCodes, bool aIsTrustedEvent, bool aIsRepeat,
1649 bool aExecute) {
1650 int32_t count, start = -1;
1651 if (Element* focusedElement = GetFocusedElement()) {
1652 start = mAccessKeys.IndexOf(focusedElement);
1653 if (start == -1 && focusedElement->IsInNativeAnonymousSubtree()) {
1654 start = mAccessKeys.IndexOf(Element::FromNodeOrNull(
1655 focusedElement->GetClosestNativeAnonymousSubtreeRootParentOrHost()));
1656 }
1657 }
1658 RefPtr<Element> element;
1659 int32_t length = mAccessKeys.Count();
1660 for (uint32_t i = 0; i < aAccessCharCodes.Length(); ++i) {
1661 uint32_t ch = aAccessCharCodes[i];
1662 nsAutoString accessKey;
1663 AppendUCS4ToUTF16(ch, accessKey);
1664 for (count = 1; count <= length; ++count) {
1665 // mAccessKeys always stores Element instances.
1666 MOZ_DIAGNOSTIC_ASSERT(length == mAccessKeys.Count())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(length == mAccessKeys.Count())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(length == mAccessKeys.Count(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("length == mAccessKeys.Count()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1666); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "length == mAccessKeys.Count()"
")"); do { *((volatile int*)__null) = 1666; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1667 element = mAccessKeys[(start + count) % length];
1668 if (IsAccessKeyTarget(element, accessKey)) {
1669 if (!aExecute) {
1670 return true;
1671 }
1672 Document* doc = element->OwnerDoc();
1673 const bool shouldActivate = [&] {
1674 if (!StaticPrefs::accessibility_accesskeycausesactivation()) {
1675 return false;
1676 }
1677 if (aIsRepeat && nsContentUtils::IsChromeDoc(doc)) {
1678 return false;
1679 }
1680
1681 // XXXedgar, Bug 1700646, maybe we could use other data structure to
1682 // make searching target with same accesskey easier, and current setup
1683 // could not ensure we cycle the target with tree order.
1684 int32_t j = 0;
1685 while (++j < length) {
1686 Element* el = mAccessKeys[(start + count + j) % length];
1687 if (IsAccessKeyTarget(el, accessKey)) {
1688 return false;
1689 }
1690 }
1691 return true;
1692 }();
1693
1694 // TODO(bug 1641171): This shouldn't be needed if we considered the
1695 // accesskey combination properly.
1696 if (aIsTrustedEvent) {
1697 doc->NotifyUserGestureActivation();
1698 }
1699
1700 auto result =
1701 element->PerformAccesskey(shouldActivate, aIsTrustedEvent);
1702 if (result.isOk()) {
1703 if (result.unwrap() && aIsTrustedEvent) {
1704 // If this is a child process, inform the parent that we want the
1705 // focus, but pass false since we don't want to change the window
1706 // order.
1707 nsIDocShell* docShell = mPresContext->GetDocShell();
1708 nsCOMPtr<nsIBrowserChild> child =
1709 docShell ? docShell->GetBrowserChild() : nullptr;
1710 if (child) {
1711 child->SendRequestFocus(false, CallerType::System);
1712 }
1713 }
1714 return true;
1715 }
1716 }
1717 }
1718 }
1719 return false;
1720}
1721
1722// static
1723void EventStateManager::GetAccessKeyLabelPrefix(Element* aElement,
1724 nsAString& aPrefix) {
1725 aPrefix.Truncate();
1726 nsAutoString separator, modifierText;
1727 nsContentUtils::GetModifierSeparatorText(separator);
1728
1729 AccessKeyType accessKeyType =
1730 GetAccessKeyTypeFor(aElement->OwnerDoc()->GetDocShell());
1731 if (accessKeyType == AccessKeyType::eNone) {
1732 return;
1733 }
1734 Modifiers modifiers = WidgetKeyboardEvent::AccessKeyModifiers(accessKeyType);
1735 if (modifiers == MODIFIER_NONE) {
1736 return;
1737 }
1738
1739 if (modifiers & MODIFIER_CONTROL) {
1740 nsContentUtils::GetControlText(modifierText);
1741 aPrefix.Append(modifierText + separator);
1742 }
1743 if (modifiers & MODIFIER_META) {
1744 nsContentUtils::GetCommandOrWinText(modifierText);
1745 aPrefix.Append(modifierText + separator);
1746 }
1747 if (modifiers & MODIFIER_ALT) {
1748 nsContentUtils::GetAltText(modifierText);
1749 aPrefix.Append(modifierText + separator);
1750 }
1751 if (modifiers & MODIFIER_SHIFT) {
1752 nsContentUtils::GetShiftText(modifierText);
1753 aPrefix.Append(modifierText + separator);
1754 }
1755}
1756
1757struct MOZ_STACK_CLASS AccessKeyInfo {
1758 WidgetKeyboardEvent* event;
1759 nsTArray<uint32_t>& charCodes;
1760
1761 AccessKeyInfo(WidgetKeyboardEvent* aEvent, nsTArray<uint32_t>& aCharCodes)
1762 : event(aEvent), charCodes(aCharCodes) {}
1763};
1764
1765bool EventStateManager::WalkESMTreeToHandleAccessKey(
1766 WidgetKeyboardEvent* aEvent, nsPresContext* aPresContext,
1767 nsTArray<uint32_t>& aAccessCharCodes, nsIDocShellTreeItem* aBubbledFrom,
1768 ProcessingAccessKeyState aAccessKeyState, bool aExecute) {
1769 EnsureDocument(mPresContext);
1770 nsCOMPtr<nsIDocShell> docShell = aPresContext->GetDocShell();
1771 if (NS_WARN_IF(!docShell)NS_warn_if_impl(!docShell, "!docShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1771)
|| NS_WARN_IF(!mDocument)NS_warn_if_impl(!mDocument, "!mDocument", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1771)
) {
1772 return false;
1773 }
1774 AccessKeyType accessKeyType = GetAccessKeyTypeFor(docShell);
1775 if (accessKeyType == AccessKeyType::eNone) {
1776 return false;
1777 }
1778 // Alt or other accesskey modifier is down, we may need to do an accesskey.
1779 if (mAccessKeys.Count() > 0 &&
1780 aEvent->ModifiersMatchWithAccessKey(accessKeyType)) {
1781 // Someone registered an accesskey. Find and activate it.
1782 if (LookForAccessKeyAndExecute(aAccessCharCodes, aEvent->IsTrusted(),
1783 aEvent->mIsRepeat, aExecute)) {
1784 return true;
1785 }
1786 }
1787
1788 int32_t childCount;
1789 docShell->GetInProcessChildCount(&childCount);
1790 for (int32_t counter = 0; counter < childCount; counter++) {
1791 // Not processing the child which bubbles up the handling
1792 nsCOMPtr<nsIDocShellTreeItem> subShellItem;
1793 docShell->GetInProcessChildAt(counter, getter_AddRefs(subShellItem));
1794 if (aAccessKeyState == eAccessKeyProcessingUp &&
1795 subShellItem == aBubbledFrom) {
1796 continue;
1797 }
1798
1799 nsCOMPtr<nsIDocShell> subDS = do_QueryInterface(subShellItem);
1800 if (subDS && IsShellVisible(subDS)) {
1801 // Guarantee subPresShell lifetime while we're handling access key
1802 // since somebody may assume that it won't be deleted before the
1803 // corresponding nsPresContext and EventStateManager.
1804 RefPtr<PresShell> subPresShell = subDS->GetPresShell();
1805
1806 // Docshells need not have a presshell (eg. display:none
1807 // iframes, docshells in transition between documents, etc).
1808 if (!subPresShell) {
1809 // Oh, well. Just move on to the next child
1810 continue;
1811 }
1812
1813 RefPtr<nsPresContext> subPresContext = subPresShell->GetPresContext();
1814
1815 RefPtr<EventStateManager> esm =
1816 static_cast<EventStateManager*>(subPresContext->EventStateManager());
1817
1818 if (esm && esm->WalkESMTreeToHandleAccessKey(
1819 aEvent, subPresContext, aAccessCharCodes, nullptr,
1820 eAccessKeyProcessingDown, aExecute)) {
1821 return true;
1822 }
1823 }
1824 } // if end . checking all sub docshell ends here.
1825
1826 // bubble up the process to the parent docshell if necessary
1827 if (eAccessKeyProcessingDown != aAccessKeyState) {
1828 nsCOMPtr<nsIDocShellTreeItem> parentShellItem;
1829 docShell->GetInProcessParent(getter_AddRefs(parentShellItem));
1830 nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parentShellItem);
1831 if (parentDS) {
1832 // Guarantee parentPresShell lifetime while we're handling access key
1833 // since somebody may assume that it won't be deleted before the
1834 // corresponding nsPresContext and EventStateManager.
1835 RefPtr<PresShell> parentPresShell = parentDS->GetPresShell();
1836 NS_ASSERTION(parentPresShell,do { if (!(parentPresShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Our PresShell exists but the parent's does not?", "parentPresShell"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1837); MOZ_PretendNoReturn(); } } while (0)
1837 "Our PresShell exists but the parent's does not?")do { if (!(parentPresShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Our PresShell exists but the parent's does not?", "parentPresShell"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1837); MOZ_PretendNoReturn(); } } while (0)
;
1838
1839 RefPtr<nsPresContext> parentPresContext =
1840 parentPresShell->GetPresContext();
1841 NS_ASSERTION(parentPresContext, "PresShell without PresContext")do { if (!(parentPresContext)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "PresShell without PresContext", "parentPresContext", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1841); MOZ_PretendNoReturn(); } } while (0)
;
1842
1843 RefPtr<EventStateManager> esm = static_cast<EventStateManager*>(
1844 parentPresContext->EventStateManager());
1845 if (esm && esm->WalkESMTreeToHandleAccessKey(
1846 aEvent, parentPresContext, aAccessCharCodes, docShell,
1847 eAccessKeyProcessingDown, aExecute)) {
1848 return true;
1849 }
1850 }
1851 } // if end. bubble up process
1852
1853 // If the content access key modifier is pressed, try remote children
1854 if (aExecute &&
1855 aEvent->ModifiersMatchWithAccessKey(AccessKeyType::eContent) &&
1856 mDocument && mDocument->GetWindow()) {
1857 // If the focus is currently on a node with a BrowserParent, the key event
1858 // should've gotten forwarded to the child process and HandleAccessKey
1859 // called from there.
1860 if (BrowserParent::GetFrom(GetFocusedElement())) {
1861 // If access key may be only in remote contents, this method won't handle
1862 // access key synchronously. In this case, only reply event should reach
1863 // here.
1864 MOZ_ASSERT(aEvent->IsHandledInRemoteProcess() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->IsHandledInRemoteProcess() || !aEvent->
IsWaitingReplyFromRemoteProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->IsHandledInRemoteProcess
() || !aEvent->IsWaitingReplyFromRemoteProcess()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aEvent->IsHandledInRemoteProcess() || !aEvent->IsWaitingReplyFromRemoteProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1865); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsHandledInRemoteProcess() || !aEvent->IsWaitingReplyFromRemoteProcess()"
")"); do { *((volatile int*)__null) = 1865; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1865 !aEvent->IsWaitingReplyFromRemoteProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->IsHandledInRemoteProcess() || !aEvent->
IsWaitingReplyFromRemoteProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->IsHandledInRemoteProcess
() || !aEvent->IsWaitingReplyFromRemoteProcess()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aEvent->IsHandledInRemoteProcess() || !aEvent->IsWaitingReplyFromRemoteProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1865); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsHandledInRemoteProcess() || !aEvent->IsWaitingReplyFromRemoteProcess()"
")"); do { *((volatile int*)__null) = 1865; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1866 }
1867 // If focus is somewhere else, then we need to check the remote children.
1868 // However, if the event has already been handled in a remote process,
1869 // then, focus is moved from the remote process after posting the event.
1870 // In such case, we shouldn't retry to handle access keys in remote
1871 // processes.
1872 else if (!aEvent->IsHandledInRemoteProcess()) {
1873 AccessKeyInfo accessKeyInfo(aEvent, aAccessCharCodes);
1874 nsContentUtils::CallOnAllRemoteChildren(
1875 mDocument->GetWindow(),
1876 [&accessKeyInfo](BrowserParent* aBrowserParent) -> CallState {
1877 // Only forward accesskeys for the active tab.
1878 if (aBrowserParent->GetDocShellIsActive()) {
1879 // Even if there is no target for the accesskey in this process,
1880 // the event may match with a content accesskey. If so, the
1881 // keyboard event should be handled with reply event for
1882 // preventing double action. (e.g., Alt+Shift+F on Windows may
1883 // focus a content in remote and open "File" menu.)
1884 accessKeyInfo.event->StopPropagation();
1885 accessKeyInfo.event->MarkAsWaitingReplyFromRemoteProcess();
1886 aBrowserParent->HandleAccessKey(*accessKeyInfo.event,
1887 accessKeyInfo.charCodes);
1888 return CallState::Stop;
1889 }
1890
1891 return CallState::Continue;
1892 });
1893 }
1894 }
1895
1896 return false;
1897} // end of HandleAccessKey
1898
1899static BrowserParent* GetBrowserParentAncestor(BrowserParent* aBrowserParent) {
1900 MOZ_ASSERT(aBrowserParent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aBrowserParent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aBrowserParent))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aBrowserParent"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1900); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aBrowserParent"
")"); do { *((volatile int*)__null) = 1900; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1901
1902 BrowserBridgeParent* bbp = aBrowserParent->GetBrowserBridgeParent();
1903 if (!bbp) {
1904 return nullptr;
1905 }
1906
1907 return bbp->Manager();
1908}
1909
1910static void DispatchCrossProcessMouseExitEvents(WidgetMouseEvent* aMouseEvent,
1911 BrowserParent* aRemoteTarget,
1912 BrowserParent* aStopAncestor,
1913 bool aIsReallyExit) {
1914 MOZ_ASSERT(aMouseEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseEvent))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aMouseEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1914); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseEvent"
")"); do { *((volatile int*)__null) = 1914; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1915 MOZ_ASSERT(aRemoteTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRemoteTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aRemoteTarget))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aRemoteTarget",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1915); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRemoteTarget"
")"); do { *((volatile int*)__null) = 1915; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1916 MOZ_ASSERT(aRemoteTarget != aStopAncestor)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRemoteTarget != aStopAncestor)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aRemoteTarget != aStopAncestor
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aRemoteTarget != aStopAncestor", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1916); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRemoteTarget != aStopAncestor"
")"); do { *((volatile int*)__null) = 1916; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1917 MOZ_ASSERT_IF(aStopAncestor, nsContentUtils::GetCommonBrowserParentAncestor(do { if (aStopAncestor) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(nsContentUtils::GetCommonBrowserParentAncestor
( aRemoteTarget, aStopAncestor))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nsContentUtils::GetCommonBrowserParentAncestor
( aRemoteTarget, aStopAncestor)))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("nsContentUtils::GetCommonBrowserParentAncestor( aRemoteTarget, aStopAncestor)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1918); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::GetCommonBrowserParentAncestor( aRemoteTarget, aStopAncestor)"
")"); do { *((volatile int*)__null) = 1918; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1918 aRemoteTarget, aStopAncestor))do { if (aStopAncestor) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(nsContentUtils::GetCommonBrowserParentAncestor
( aRemoteTarget, aStopAncestor))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nsContentUtils::GetCommonBrowserParentAncestor
( aRemoteTarget, aStopAncestor)))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("nsContentUtils::GetCommonBrowserParentAncestor( aRemoteTarget, aStopAncestor)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1918); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::GetCommonBrowserParentAncestor( aRemoteTarget, aStopAncestor)"
")"); do { *((volatile int*)__null) = 1918; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1919
1920 while (aRemoteTarget != aStopAncestor) {
1921 UniquePtr<WidgetMouseEvent> mouseExitEvent =
1922 CreateMouseOrPointerWidgetEvent(aMouseEvent, eMouseExitFromWidget,
1923 aMouseEvent->mRelatedTarget);
1924 mouseExitEvent->mExitFrom =
1925 Some(aIsReallyExit ? WidgetMouseEvent::ePuppet
1926 : WidgetMouseEvent::ePuppetParentToPuppetChild);
1927 aRemoteTarget->SendRealMouseEvent(*mouseExitEvent);
1928
1929 aRemoteTarget = GetBrowserParentAncestor(aRemoteTarget);
1930 }
1931}
1932
1933void EventStateManager::DispatchCrossProcessEvent(WidgetEvent* aEvent,
1934 BrowserParent* aRemoteTarget,
1935 nsEventStatus* aStatus) {
1936 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1936); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 1936; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1937 MOZ_ASSERT(aRemoteTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRemoteTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aRemoteTarget))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aRemoteTarget",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1937); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRemoteTarget"
")"); do { *((volatile int*)__null) = 1937; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1938 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1938); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 1938; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1939
1940 BrowserParent* remote = aRemoteTarget;
1941
1942 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
1943 bool isContextMenuKey = mouseEvent && mouseEvent->IsContextMenuKeyEvent();
1944 if (aEvent->mClass == eKeyboardEventClass || isContextMenuKey) {
1945 // APZ attaches a LayersId to hit-testable events, for keyboard events,
1946 // we use focus.
1947 BrowserParent* preciseRemote = BrowserParent::GetFocused();
1948 if (preciseRemote) {
1949 remote = preciseRemote;
1950 }
1951 // else there is a race between layout and focus tracking,
1952 // so fall back to delivering the event to the topmost child process.
1953 } else if (aEvent->mLayersId.IsValid()) {
1954 BrowserParent* preciseRemote =
1955 BrowserParent::GetBrowserParentFromLayersId(aEvent->mLayersId);
1956 if (preciseRemote) {
1957 remote = preciseRemote;
1958 }
1959 // else there is a race between APZ and the LayersId to BrowserParent
1960 // mapping, so fall back to delivering the event to the topmost child
1961 // process.
1962 }
1963
1964 MOZ_ASSERT(aEvent->mMessage != ePointerClick)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage != ePointerClick)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage != ePointerClick
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aEvent->mMessage != ePointerClick", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1964); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage != ePointerClick"
")"); do { *((volatile int*)__null) = 1964; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1965 MOZ_ASSERT(aEvent->mMessage != ePointerAuxClick)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage != ePointerAuxClick)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage != ePointerAuxClick))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage != ePointerAuxClick"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1965); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage != ePointerAuxClick"
")"); do { *((volatile int*)__null) = 1965; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1966
1967 // SendReal* will transform the coordinate to the child process coordinate
1968 // space. So restore the coordinate after the event has been dispatched to the
1969 // child process to avoid using the transformed coordinate afterward.
1970 AutoRestore<LayoutDeviceIntPoint> restore(aEvent->mRefPoint);
1971 switch (aEvent->mClass) {
1972 case ePointerEventClass:
1973 MOZ_ASSERT(aEvent->mMessage == eContextMenu)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eContextMenu)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eContextMenu
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aEvent->mMessage == eContextMenu", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1973); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eContextMenu"
")"); do { *((volatile int*)__null) = 1973; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1974 [[fallthrough]];
1975 case eMouseEventClass: {
1976 BrowserParent* oldRemote = BrowserParent::GetLastMouseRemoteTarget();
1977
1978 // If this is a eMouseExitFromWidget event, need to redirect the event to
1979 // the last remote and and notify all its ancestors about the exit, if
1980 // any.
1981 if (mouseEvent->mMessage == eMouseExitFromWidget) {
1982 MOZ_ASSERT(mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mouseEvent->mExitFrom.value() == WidgetMouseEvent
::ePuppet)>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(mouseEvent->mExitFrom.value() ==
WidgetMouseEvent::ePuppet))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1982); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
")"); do { *((volatile int*)__null) = 1982; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1983 MOZ_ASSERT(mouseEvent->mReason == WidgetMouseEvent::eReal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mouseEvent->mReason == WidgetMouseEvent::eReal)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mouseEvent->mReason == WidgetMouseEvent::eReal)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("mouseEvent->mReason == WidgetMouseEvent::eReal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1983); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mReason == WidgetMouseEvent::eReal"
")"); do { *((volatile int*)__null) = 1983; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1984 MOZ_ASSERT(!mouseEvent->mLayersId.IsValid())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mouseEvent->mLayersId.IsValid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mouseEvent->mLayersId.IsValid
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mouseEvent->mLayersId.IsValid()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1984); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mouseEvent->mLayersId.IsValid()"
")"); do { *((volatile int*)__null) = 1984; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1985 MOZ_ASSERT(remote->GetBrowserHost())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(remote->GetBrowserHost())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(remote->GetBrowserHost())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("remote->GetBrowserHost()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1985); AnnotateMozCrashReason("MOZ_ASSERT" "(" "remote->GetBrowserHost()"
")"); do { *((volatile int*)__null) = 1985; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1986
1987 if (oldRemote && oldRemote != remote) {
1988 Unused << NS_WARN_IF(nsContentUtils::GetCommonBrowserParentAncestor(NS_warn_if_impl(nsContentUtils::GetCommonBrowserParentAncestor
( remote, oldRemote) != remote, "nsContentUtils::GetCommonBrowserParentAncestor( remote, oldRemote) != remote"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1989)
1989 remote, oldRemote) != remote)NS_warn_if_impl(nsContentUtils::GetCommonBrowserParentAncestor
( remote, oldRemote) != remote, "nsContentUtils::GetCommonBrowserParentAncestor( remote, oldRemote) != remote"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1989)
;
1990 remote = oldRemote;
1991 }
1992
1993 DispatchCrossProcessMouseExitEvents(mouseEvent, remote, nullptr, true);
1994 return;
1995 }
1996
1997 if (BrowserParent* pointerLockedRemote =
1998 PointerLockManager::GetLockedRemoteTarget()) {
1999 remote = pointerLockedRemote;
2000 } else if (BrowserParent* pointerCapturedRemote =
2001 PointerEventHandler::GetPointerCapturingRemoteTarget(
2002 mouseEvent->pointerId)) {
2003 remote = pointerCapturedRemote;
2004 } else if (BrowserParent* capturingRemote =
2005 PresShell::GetCapturingRemoteTarget()) {
2006 remote = capturingRemote;
2007 }
2008
2009 // If a mouse is over a remote target A, and then moves to
2010 // remote target B, we'd deliver the event directly to remote target B
2011 // after the moving, A would never get notified that the mouse left.
2012 // So we generate a exit event to notify A after the move.
2013 // XXXedgar, if the synthesized mouse events could deliver to the correct
2014 // process directly (see
2015 // https://bugzilla.mozilla.org/show_bug.cgi?id=1549355), we probably
2016 // don't need to check mReason then.
2017 if (mouseEvent->mReason == WidgetMouseEvent::eReal &&
2018 remote != oldRemote) {
2019 MOZ_ASSERT(mouseEvent->mMessage != eMouseExitFromWidget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mouseEvent->mMessage != eMouseExitFromWidget)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mouseEvent->mMessage != eMouseExitFromWidget))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mouseEvent->mMessage != eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2019); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mMessage != eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 2019; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2020 if (oldRemote) {
2021 BrowserParent* commonAncestor =
2022 nsContentUtils::GetCommonBrowserParentAncestor(remote, oldRemote);
2023 if (commonAncestor == oldRemote) {
2024 // Mouse moves to the inner OOP frame, it is not a really exit.
2025 DispatchCrossProcessMouseExitEvents(
2026 mouseEvent, GetBrowserParentAncestor(remote),
2027 GetBrowserParentAncestor(commonAncestor), false);
2028 } else if (commonAncestor == remote) {
2029 // Mouse moves to the outer OOP frame, it is a really exit.
2030 DispatchCrossProcessMouseExitEvents(mouseEvent, oldRemote,
2031 commonAncestor, true);
2032 } else {
2033 // Mouse moves to OOP frame in other subtree, it is a really exit,
2034 // need to notify all its ancestors before common ancestor about the
2035 // exit.
2036 DispatchCrossProcessMouseExitEvents(mouseEvent, oldRemote,
2037 commonAncestor, true);
2038 if (commonAncestor) {
2039 UniquePtr<WidgetMouseEvent> mouseExitEvent =
2040 CreateMouseOrPointerWidgetEvent(mouseEvent,
2041 eMouseExitFromWidget,
2042 mouseEvent->mRelatedTarget);
2043 mouseExitEvent->mExitFrom =
2044 Some(WidgetMouseEvent::ePuppetParentToPuppetChild);
2045 commonAncestor->SendRealMouseEvent(*mouseExitEvent);
2046 }
2047 }
2048 }
2049
2050 if (mouseEvent->mMessage != eMouseExitFromWidget &&
2051 mouseEvent->mMessage != eMouseEnterIntoWidget) {
2052 // This is to make cursor would be updated correctly.
2053 remote->MouseEnterIntoWidget();
2054 }
2055 }
2056
2057 remote->SendRealMouseEvent(*mouseEvent);
2058 return;
2059 }
2060 case eKeyboardEventClass: {
2061 auto* keyboardEvent = aEvent->AsKeyboardEvent();
2062 if (aEvent->mMessage == eKeyUp) {
2063 HandleKeyUpInteraction(keyboardEvent);
2064 }
2065 remote->SendRealKeyEvent(*keyboardEvent);
2066 return;
2067 }
2068 case eWheelEventClass: {
2069 if (BrowserParent* pointerLockedRemote =
2070 PointerLockManager::GetLockedRemoteTarget()) {
2071 remote = pointerLockedRemote;
2072 }
2073 remote->SendMouseWheelEvent(*aEvent->AsWheelEvent());
2074 return;
2075 }
2076 case eTouchEventClass: {
2077 // Let the child process synthesize a mouse event if needed, and
2078 // ensure we don't synthesize one in this process.
2079 *aStatus = nsEventStatus_eConsumeNoDefault;
2080 remote->SendRealTouchEvent(*aEvent->AsTouchEvent());
2081 return;
2082 }
2083 case eDragEventClass: {
2084 RefPtr<BrowserParent> browserParent = remote;
2085 browserParent->MaybeInvokeDragSession(aEvent->mMessage);
2086
2087 RefPtr<nsIWidget> widget = browserParent->GetTopLevelWidget();
2088 nsCOMPtr<nsIDragSession> dragSession =
2089 nsContentUtils::GetDragSession(widget);
2090 uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
2091 uint32_t action = nsIDragService::DRAGDROP_ACTION_NONE;
2092 nsCOMPtr<nsIPrincipal> principal;
2093 nsCOMPtr<nsIContentSecurityPolicy> csp;
2094
2095 if (dragSession) {
2096 dragSession->DragEventDispatchedToChildProcess();
2097 dragSession->GetDragAction(&action);
2098 dragSession->GetTriggeringPrincipal(getter_AddRefs(principal));
2099 dragSession->GetCsp(getter_AddRefs(csp));
2100 RefPtr<DataTransfer> initialDataTransfer =
2101 dragSession->GetDataTransfer();
2102 if (initialDataTransfer) {
2103 dropEffect = initialDataTransfer->DropEffectInt();
2104 }
2105 }
2106
2107 browserParent->SendRealDragEvent(*aEvent->AsDragEvent(), action,
2108 dropEffect, principal, csp);
2109 return;
2110 }
2111 default: {
2112 MOZ_CRASH("Attempt to send non-whitelisted event?")do { do { } while (false); MOZ_ReportCrash("" "Attempt to send non-whitelisted event?"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2112); AnnotateMozCrashReason("MOZ_CRASH(" "Attempt to send non-whitelisted event?"
")"); do { *((volatile int*)__null) = 2112; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2113 }
2114 }
2115}
2116
2117bool EventStateManager::IsRemoteTarget(nsIContent* target) {
2118 return BrowserParent::GetFrom(target) || BrowserBridgeChild::GetFrom(target);
2119}
2120
2121bool EventStateManager::IsTopLevelRemoteTarget(nsIContent* target) {
2122 return !!BrowserParent::GetFrom(target);
2123}
2124
2125bool EventStateManager::HandleCrossProcessEvent(WidgetEvent* aEvent,
2126 nsEventStatus* aStatus) {
2127 if (!aEvent->CanBeSentToRemoteProcess()) {
2128 return false;
2129 }
2130
2131 MOZ_ASSERT(!aEvent->HasBeenPostedToRemoteProcess(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEvent->HasBeenPostedToRemoteProcess())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aEvent->HasBeenPostedToRemoteProcess()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aEvent->HasBeenPostedToRemoteProcess()"
" (" "Why do we need to post same event to remote processes again?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2132); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aEvent->HasBeenPostedToRemoteProcess()"
") (" "Why do we need to post same event to remote processes again?"
")"); do { *((volatile int*)__null) = 2132; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2132 "Why do we need to post same event to remote processes again?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEvent->HasBeenPostedToRemoteProcess())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aEvent->HasBeenPostedToRemoteProcess()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aEvent->HasBeenPostedToRemoteProcess()"
" (" "Why do we need to post same event to remote processes again?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2132); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aEvent->HasBeenPostedToRemoteProcess()"
") (" "Why do we need to post same event to remote processes again?"
")"); do { *((volatile int*)__null) = 2132; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2133
2134 // Collect the remote event targets we're going to forward this
2135 // event to.
2136 //
2137 // NB: the elements of |remoteTargets| must be unique, for correctness.
2138 AutoTArray<RefPtr<BrowserParent>, 1> remoteTargets;
2139 if (aEvent->mClass != eTouchEventClass || aEvent->mMessage == eTouchStart) {
2140 // If this event only has one target, and it's remote, add it to
2141 // the array.
2142 nsIFrame* frame = aEvent->mMessage == eDragExit
2143 ? sLastDragOverFrame.GetFrame()
2144 : GetEventTarget();
2145 nsIContent* target = frame ? frame->GetContent() : nullptr;
2146 if (BrowserParent* remoteTarget = BrowserParent::GetFrom(target)) {
2147 remoteTargets.AppendElement(remoteTarget);
2148 }
2149 } else {
2150 // This is a touch event with possibly multiple touch points.
2151 // Each touch point may have its own target. So iterate through
2152 // all of them and collect the unique set of targets for event
2153 // forwarding.
2154 //
2155 // This loop is similar to the one used in
2156 // PresShell::DispatchTouchEvent().
2157 const WidgetTouchEvent::TouchArray& touches =
2158 aEvent->AsTouchEvent()->mTouches;
2159 for (uint32_t i = 0; i < touches.Length(); ++i) {
2160 Touch* touch = touches[i];
2161 // NB: the |mChanged| check is an optimization, subprocesses can
2162 // compute this for themselves. If the touch hasn't changed, we
2163 // may be able to avoid forwarding the event entirely (which is
2164 // not free).
2165 if (!touch || !touch->mChanged) {
2166 continue;
2167 }
2168 nsCOMPtr<EventTarget> targetPtr = touch->mTarget;
2169 if (!targetPtr) {
2170 continue;
2171 }
2172 nsCOMPtr<nsIContent> target = do_QueryInterface(targetPtr);
2173 BrowserParent* remoteTarget = BrowserParent::GetFrom(target);
2174 if (remoteTarget && !remoteTargets.Contains(remoteTarget)) {
2175 remoteTargets.AppendElement(remoteTarget);
2176 }
2177 }
2178 }
2179
2180 if (remoteTargets.Length() == 0) {
2181 return false;
2182 }
2183
2184 // Dispatch the event to the remote target.
2185 for (uint32_t i = 0; i < remoteTargets.Length(); ++i) {
2186 DispatchCrossProcessEvent(aEvent, remoteTargets[i], aStatus);
2187 }
2188 return aEvent->HasBeenPostedToRemoteProcess();
2189}
2190
2191//
2192// CreateClickHoldTimer
2193//
2194// Fire off a timer for determining if the user wants click-hold. This timer
2195// is a one-shot that will be cancelled when the user moves enough to fire
2196// a drag.
2197//
2198void EventStateManager::CreateClickHoldTimer(nsPresContext* inPresContext,
2199 nsIFrame* inDownFrame,
2200 WidgetGUIEvent* inMouseDownEvent) {
2201 if (!inMouseDownEvent->IsTrusted() ||
2202 IsTopLevelRemoteTarget(mGestureDownContent) ||
2203 PointerLockManager::IsLocked()) {
2204 return;
2205 }
2206
2207 // just to be anal (er, safe)
2208 if (mClickHoldTimer) {
2209 mClickHoldTimer->Cancel();
2210 mClickHoldTimer = nullptr;
2211 }
2212
2213 // if content clicked on has a popup, don't even start the timer
2214 // since we'll end up conflicting and both will show.
2215 if (mGestureDownContent &&
2216 nsContentUtils::HasNonEmptyAttr(mGestureDownContent, kNameSpaceID_None,
2217 nsGkAtoms::popup)) {
2218 return;
2219 }
2220
2221 int32_t clickHoldDelay = StaticPrefs::ui_click_hold_context_menus_delay();
2222 NS_NewTimerWithFuncCallback(
2223 getter_AddRefs(mClickHoldTimer), sClickHoldCallback, this, clickHoldDelay,
2224 nsITimer::TYPE_ONE_SHOT, "EventStateManager::CreateClickHoldTimer");
2225} // CreateClickHoldTimer
2226
2227//
2228// KillClickHoldTimer
2229//
2230// Stop the timer that would show the context menu dead in its tracks
2231//
2232void EventStateManager::KillClickHoldTimer() {
2233 if (mClickHoldTimer) {
2234 mClickHoldTimer->Cancel();
2235 mClickHoldTimer = nullptr;
2236 }
2237}
2238
2239//
2240// sClickHoldCallback
2241//
2242// This fires after the mouse has been down for a certain length of time.
2243//
2244void EventStateManager::sClickHoldCallback(nsITimer* aTimer, void* aESM) {
2245 RefPtr<EventStateManager> self = static_cast<EventStateManager*>(aESM);
2246 if (self) {
2247 self->FireContextClick();
2248 }
2249
2250 // NOTE: |aTimer| and |self->mAutoHideTimer| are invalid after calling
2251 // ClosePopup();
2252
2253} // sAutoHideCallback
2254
2255//
2256// FireContextClick
2257//
2258// If we're this far, our timer has fired, which means the mouse has been down
2259// for a certain period of time and has not moved enough to generate a
2260// dragGesture. We can be certain the user wants a context-click at this stage,
2261// so generate a dom event and fire it in.
2262//
2263// After the event fires, check if PreventDefault() has been set on the event
2264// which means that someone either ate the event or put up a context menu. This
2265// is our cue to stop tracking the drag gesture. If we always did this,
2266// draggable items w/out a context menu wouldn't be draggable after a certain
2267// length of time, which is _not_ what we want.
2268//
2269void EventStateManager::FireContextClick() {
2270 if (!mGestureDownContent || !mPresContext || PointerLockManager::IsLocked()) {
2271 return;
2272 }
2273
2274#ifdef XP_MACOSX
2275 // Hack to ensure that we don't show a context menu when the user
2276 // let go of the mouse after a long cpu-hogging operation prevented
2277 // us from handling any OS events. See bug 117589.
2278 if (!CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState,
2279 kCGMouseButtonLeft))
2280 return;
2281#endif
2282
2283 nsEventStatus status = nsEventStatus_eIgnore;
2284
2285 // Dispatch to the DOM. We have to fake out the ESM and tell it that the
2286 // current target frame is actually where the mouseDown occurred, otherwise it
2287 // will use the frame the mouse is currently over which may or may not be
2288 // the same. (Note: saari and I have decided that we don't have to reset
2289 // |mCurrentTarget| when we're through because no one else is doing anything
2290 // more with this event and it will get reset on the very next event to the
2291 // correct frame).
2292 mCurrentTarget = mPresContext->GetPrimaryFrameFor(mGestureDownContent);
2293 // make sure the widget sticks around
2294 nsCOMPtr<nsIWidget> targetWidget;
2295 if (mCurrentTarget && (targetWidget = mCurrentTarget->GetNearestWidget())) {
2296 NS_ASSERTION(do { if (!(mPresContext == mCurrentTarget->PresContext()))
{ NS_DebugBreak(NS_DEBUG_ASSERTION, "a prescontext returned a primary frame that didn't belong to it?"
, "mPresContext == mCurrentTarget->PresContext()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2298); MOZ_PretendNoReturn(); } } while (0)
2297 mPresContext == mCurrentTarget->PresContext(),do { if (!(mPresContext == mCurrentTarget->PresContext()))
{ NS_DebugBreak(NS_DEBUG_ASSERTION, "a prescontext returned a primary frame that didn't belong to it?"
, "mPresContext == mCurrentTarget->PresContext()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2298); MOZ_PretendNoReturn(); } } while (0)
2298 "a prescontext returned a primary frame that didn't belong to it?")do { if (!(mPresContext == mCurrentTarget->PresContext()))
{ NS_DebugBreak(NS_DEBUG_ASSERTION, "a prescontext returned a primary frame that didn't belong to it?"
, "mPresContext == mCurrentTarget->PresContext()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2298); MOZ_PretendNoReturn(); } } while (0)
;
2299
2300 // before dispatching, check that we're not on something that
2301 // doesn't get a context menu
2302 bool allowedToDispatch = true;
2303
2304 if (mGestureDownContent->IsAnyOfXULElements(nsGkAtoms::scrollbar,
2305 nsGkAtoms::scrollbarbutton,
2306 nsGkAtoms::button)) {
2307 allowedToDispatch = false;
2308 } else if (mGestureDownContent->IsXULElement(nsGkAtoms::toolbarbutton)) {
2309 // a <toolbarbutton> that has the container attribute set
2310 // will already have its own dropdown.
2311 if (nsContentUtils::HasNonEmptyAttr(
2312 mGestureDownContent, kNameSpaceID_None, nsGkAtoms::container)) {
2313 allowedToDispatch = false;
2314 } else {
2315 // If the toolbar button has an open menu, don't attempt to open
2316 // a second menu
2317 if (mGestureDownContent->IsElement() &&
2318 mGestureDownContent->AsElement()->AttrValueIs(
2319 kNameSpaceID_None, nsGkAtoms::open, nsGkAtoms::_true,
2320 eCaseMatters)) {
2321 allowedToDispatch = false;
2322 }
2323 }
2324 } else if (mGestureDownContent->IsHTMLElement()) {
2325 if (const auto* formCtrl =
2326 nsIFormControl::FromNode(mGestureDownContent)) {
2327 allowedToDispatch =
2328 formCtrl->IsTextControl(/*aExcludePassword*/ false) ||
2329 formCtrl->ControlType() == FormControlType::InputFile;
2330 } else if (mGestureDownContent->IsAnyOfHTMLElements(
2331 nsGkAtoms::embed, nsGkAtoms::object, nsGkAtoms::label)) {
2332 allowedToDispatch = false;
2333 }
2334 }
2335
2336 if (allowedToDispatch) {
2337 // init the event while mCurrentTarget is still good
2338 WidgetPointerEvent event(true, eContextMenu, targetWidget);
2339 event.mClickCount = 1;
2340 FillInEventFromGestureDown(&event);
2341
2342 // we need to forget the clicking content and click count for the
2343 // following eMouseUp event when click-holding context menus
2344 LastMouseDownInfo& mouseDownInfo = GetLastMouseDownInfo(event.mButton);
2345 mouseDownInfo.mLastMouseDownContent = nullptr;
2346 mouseDownInfo.mClickCount = 0;
2347 mouseDownInfo.mLastMouseDownInputControlType = Nothing();
2348
2349 // stop selection tracking, we're in control now
2350 if (mCurrentTarget) {
2351 RefPtr<nsFrameSelection> frameSel = mCurrentTarget->GetFrameSelection();
2352
2353 if (frameSel && frameSel->GetDragState()) {
2354 // note that this can cause selection changed events to fire if we're
2355 // in a text field, which will null out mCurrentTarget
2356 frameSel->SetDragState(false);
2357 }
2358 }
2359
2360 AutoHandlingUserInputStatePusher userInpStatePusher(true, &event);
2361
2362 // dispatch to DOM
2363 RefPtr<nsPresContext> presContext = mPresContext;
2364
2365 // The contextmenu event handled by PresShell will apply to elements (not
2366 // all nodes) correctly and will be dispatched to EventStateManager for
2367 // further handling preventing click event and stopping tracking drag
2368 // gesture.
2369 if (RefPtr<PresShell> presShell = presContext->GetPresShell()) {
2370 presShell->HandleEvent(mCurrentTarget, &event, false, &status);
2371 }
2372
2373 // We don't need to dispatch to frame handling because no frames
2374 // watch eContextMenu except for nsMenuFrame and that's only for
2375 // dismissal. That's just as well since we don't really know
2376 // which frame to send it to.
2377 }
2378 }
2379
2380 // stop tracking a drag whatever the event has been handled or not.
2381 StopTrackingDragGesture(true);
2382
2383 KillClickHoldTimer();
2384
2385} // FireContextClick
2386
2387//
2388// BeginTrackingDragGesture
2389//
2390// Record that the mouse has gone down and that we should move to TRACKING state
2391// of d&d gesture tracker.
2392//
2393// We also use this to track click-hold context menus. When the mouse goes down,
2394// fire off a short timer. If the timer goes off and we have yet to fire the
2395// drag gesture (ie, the mouse hasn't moved a certain distance), then we can
2396// assume the user wants a click-hold, so fire a context-click event. We only
2397// want to cancel the drag gesture if the context-click event is handled.
2398//
2399void EventStateManager::BeginTrackingDragGesture(nsPresContext* aPresContext,
2400 WidgetMouseEvent* inDownEvent,
2401 nsIFrame* inDownFrame) {
2402 if (!inDownEvent->mWidget) {
2403 return;
2404 }
2405
2406 // Note that |inDownEvent| could be either a mouse down event or a
2407 // synthesized mouse move event.
2408 SetGestureDownPoint(inDownEvent);
2409
2410 if (inDownFrame) {
2411 inDownFrame->GetContentForEvent(inDownEvent,
2412 getter_AddRefs(mGestureDownContent));
2413
2414 mGestureDownFrameOwner = inDownFrame->GetContent();
2415 if (!mGestureDownFrameOwner) {
2416 mGestureDownFrameOwner = mGestureDownContent;
2417 }
2418 }
2419 mGestureModifiers = inDownEvent->mModifiers;
2420 mGestureDownButtons = inDownEvent->mButtons;
2421 mGestureDownButton = inDownEvent->mButton;
2422
2423 if (inDownEvent->mMessage != eMouseTouchDrag &&
2424 StaticPrefs::ui_click_hold_context_menus()) {
2425 // fire off a timer to track click-hold
2426 CreateClickHoldTimer(aPresContext, inDownFrame, inDownEvent);
2427 }
2428}
2429
2430void EventStateManager::SetGestureDownPoint(WidgetGUIEvent* aEvent) {
2431 mGestureDownPoint =
2432 GetEventRefPoint(aEvent) + aEvent->mWidget->WidgetToScreenOffset();
2433}
2434
2435LayoutDeviceIntPoint EventStateManager::GetEventRefPoint(
2436 WidgetEvent* aEvent) const {
2437 auto touchEvent = aEvent->AsTouchEvent();
2438 return (touchEvent && !touchEvent->mTouches.IsEmpty())
2439 ? aEvent->AsTouchEvent()->mTouches[0]->mRefPoint
2440 : aEvent->mRefPoint;
2441}
2442
2443void EventStateManager::BeginTrackingRemoteDragGesture(
2444 nsIContent* aContent, RemoteDragStartData* aDragStartData) {
2445 mGestureDownContent = aContent;
2446 mGestureDownFrameOwner = aContent;
2447 mGestureDownInTextControl =
2448 aContent && aContent->IsInNativeAnonymousSubtree() &&
2449 TextControlElement::FromNodeOrNull(
2450 aContent->GetClosestNativeAnonymousSubtreeRootParentOrHost());
2451 mGestureDownDragStartData = aDragStartData;
2452}
2453
2454//
2455// StopTrackingDragGesture
2456//
2457// Record that the mouse has gone back up so that we should leave the TRACKING
2458// state of d&d gesture tracker and return to the START state.
2459//
2460void EventStateManager::StopTrackingDragGesture(bool aClearInChildProcesses) {
2461 mGestureDownContent = nullptr;
2462 mGestureDownFrameOwner = nullptr;
2463 mGestureDownInTextControl = false;
2464 mGestureDownDragStartData = nullptr;
2465
2466 // If a content process starts a drag but the mouse is released before the
2467 // parent starts the actual drag, the content process will think a drag is
2468 // still happening. Inform any child processes with active drags that the drag
2469 // should be stopped.
2470 if (!aClearInChildProcesses || !XRE_IsParentProcess()) {
2471 return;
2472 }
2473
2474 // Only notify if there is NOT a drag session active in the parent.
2475 RefPtr<nsIDragSession> dragSession =
2476 nsContentUtils::GetDragSession(mPresContext);
2477 if (dragSession) {
2478 return;
2479 }
2480 nsCOMPtr<nsIDragService> dragService =
2481 do_GetService("@mozilla.org/widget/dragservice;1");
2482 if (!dragService) {
2483 return;
2484 }
2485 dragService->RemoveAllBrowsers();
2486}
2487
2488void EventStateManager::FillInEventFromGestureDown(WidgetMouseEvent* aEvent) {
2489 NS_ASSERTION(aEvent->mWidget == mCurrentTarget->GetNearestWidget(),do { if (!(aEvent->mWidget == mCurrentTarget->GetNearestWidget
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Incorrect widget in event"
, "aEvent->mWidget == mCurrentTarget->GetNearestWidget()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2490); MOZ_PretendNoReturn(); } } while (0)
2490 "Incorrect widget in event")do { if (!(aEvent->mWidget == mCurrentTarget->GetNearestWidget
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Incorrect widget in event"
, "aEvent->mWidget == mCurrentTarget->GetNearestWidget()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2490); MOZ_PretendNoReturn(); } } while (0)
;
2491
2492 // Set the coordinates in the new event to the coordinates of
2493 // the old event, adjusted for the fact that the widget might be
2494 // different
2495 aEvent->mRefPoint =
2496 mGestureDownPoint - aEvent->mWidget->WidgetToScreenOffset();
2497 aEvent->mModifiers = mGestureModifiers;
2498 aEvent->mButtons = mGestureDownButtons;
2499 if (aEvent->mMessage == eContextMenu) {
2500 aEvent->mButton = mGestureDownButton;
2501 }
2502}
2503
2504void EventStateManager::MaybeFirePointerCancel(WidgetInputEvent* aEvent) {
2505 RefPtr<PresShell> presShell = mPresContext->GetPresShell();
2506 AutoWeakFrame targetFrame = mCurrentTarget;
2507
2508 if (!presShell || !targetFrame) {
2509 return;
2510 }
2511
2512 nsCOMPtr<nsIContent> content;
2513 targetFrame->GetContentForEvent(aEvent, getter_AddRefs(content));
2514 if (!content) {
2515 return;
2516 }
2517
2518 nsEventStatus status = nsEventStatus_eIgnore;
2519
2520 if (WidgetMouseEvent* aMouseEvent = aEvent->AsMouseEvent()) {
2521 WidgetPointerEvent event(*aMouseEvent);
2522 PointerEventHandler::InitPointerEventFromMouse(&event, aMouseEvent,
2523 ePointerCancel);
2524
2525 event.convertToPointer = false;
2526 presShell->HandleEventWithTarget(&event, targetFrame, content, &status);
2527 } else if (WidgetTouchEvent* aTouchEvent = aEvent->AsTouchEvent()) {
2528 WidgetPointerEvent event(aTouchEvent->IsTrusted(), ePointerCancel,
2529 aTouchEvent->mWidget);
2530
2531 PointerEventHandler::InitPointerEventFromTouch(event, *aTouchEvent,
2532 *aTouchEvent->mTouches[0]);
2533
2534 event.convertToPointer = false;
2535 presShell->HandleEventWithTarget(&event, targetFrame, content, &status);
2536 } else {
2537 MOZ_ASSERT(false)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2537); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ")")
; do { *((volatile int*)__null) = 2537; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2538 }
2539
2540 // HandleEventWithTarget clears out mCurrentTarget, which may be used in the
2541 // caller GenerateDragGesture. We have to restore mCurrentTarget.
2542 mCurrentTarget = targetFrame;
2543}
2544
2545bool EventStateManager::IsEventOutsideDragThreshold(
2546 WidgetInputEvent* aEvent) const {
2547 static int32_t sPixelThresholdX = 0;
2548 static int32_t sPixelThresholdY = 0;
2549
2550 if (!sPixelThresholdX) {
2551 sPixelThresholdX =
2552 LookAndFeel::GetInt(LookAndFeel::IntID::DragThresholdX, 0);
2553 sPixelThresholdY =
2554 LookAndFeel::GetInt(LookAndFeel::IntID::DragThresholdY, 0);
2555 if (sPixelThresholdX <= 0) {
2556 sPixelThresholdX = 5;
2557 }
2558 if (sPixelThresholdY <= 0) {
2559 sPixelThresholdY = 5;
2560 }
2561 }
2562
2563 LayoutDeviceIntPoint pt =
2564 aEvent->mWidget->WidgetToScreenOffset() + GetEventRefPoint(aEvent);
2565 LayoutDeviceIntPoint distance = pt - mGestureDownPoint;
2566 return Abs(distance.x) > sPixelThresholdX ||
2567 Abs(distance.y) > sPixelThresholdY;
2568}
2569
2570//
2571// GenerateDragGesture
2572//
2573// If we're in the TRACKING state of the d&d gesture tracker, check the current
2574// position of the mouse in relation to the old one. If we've moved a sufficient
2575// amount from the mouse down, then fire off a drag gesture event.
2576void EventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
2577 WidgetInputEvent* aEvent) {
2578 NS_ASSERTION(aPresContext, "This shouldn't happen.")do { if (!(aPresContext)) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"This shouldn't happen.", "aPresContext", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2578); MOZ_PretendNoReturn(); } } while (0)
;
2579 if (!IsTrackingDragGesture()) {
2580 return;
2581 }
2582
2583 AutoWeakFrame targetFrameBefore = mCurrentTarget;
2584 auto autoRestore = MakeScopeExit([&] { mCurrentTarget = targetFrameBefore; });
2585 mCurrentTarget = mGestureDownFrameOwner->GetPrimaryFrame();
2586
2587 if (!mCurrentTarget || !mCurrentTarget->GetNearestWidget()) {
2588 StopTrackingDragGesture(true);
2589 return;
2590 }
2591
2592 // Check if selection is tracking drag gestures, if so
2593 // don't interfere!
2594 if (mCurrentTarget) {
2595 RefPtr<nsFrameSelection> frameSel = mCurrentTarget->GetFrameSelection();
2596 if (frameSel && frameSel->GetDragState()) {
2597 StopTrackingDragGesture(true);
2598 return;
2599 }
2600 }
2601
2602 // If non-native code is capturing the mouse don't start a drag.
2603 if (PresShell::IsMouseCapturePreventingDrag()) {
2604 StopTrackingDragGesture(true);
2605 return;
2606 }
2607
2608 if (!IsEventOutsideDragThreshold(aEvent)) {
2609 // To keep the old behavior, flush layout even if we don't start dnd.
2610 FlushLayout(aPresContext);
2611 return;
2612 }
2613
2614 if (StaticPrefs::ui_click_hold_context_menus()) {
2615 // stop the click-hold before we fire off the drag gesture, in case
2616 // it takes a long time
2617 KillClickHoldTimer();
2618 }
2619
2620 nsCOMPtr<nsIDocShell> docshell = aPresContext->GetDocShell();
2621 if (!docshell) {
2622 return;
2623 }
2624
2625 nsCOMPtr<nsPIDOMWindowOuter> window = docshell->GetWindow();
2626 if (!window) return;
2627
2628 RefPtr<DataTransfer> dataTransfer =
2629 new DataTransfer(window, eDragStart, /* aIsExternal */ false,
2630 /* aClipboardType */ Nothing());
2631 auto protectDataTransfer = MakeScopeExit([&] {
2632 if (dataTransfer) {
2633 dataTransfer->Disconnect();
2634 }
2635 });
2636
2637 RefPtr<Selection> selection;
2638 RefPtr<RemoteDragStartData> remoteDragStartData;
2639 nsCOMPtr<nsIContent> eventContent, targetContent;
2640 nsCOMPtr<nsIPrincipal> principal;
2641 nsCOMPtr<nsIContentSecurityPolicy> csp;
2642 nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
2643 bool allowEmptyDataTransfer = false;
2644 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(eventContent));
2645 if (eventContent) {
2646 // If the content is a text node in a password field, we shouldn't
2647 // allow to drag its raw text. Note that we've supported drag from
2648 // password fields but dragging data was masked text. So, it doesn't
2649 // make sense anyway.
2650 if (eventContent->IsText() && eventContent->HasFlag(NS_MAYBE_MASKED)) {
2651 // However, it makes sense to allow to drag selected password text
2652 // when copying selected password is allowed because users may want
2653 // to use drag and drop rather than copy and paste when web apps
2654 // request to input password twice for conforming new password but
2655 // they used password generator.
2656 TextEditor* textEditor =
2657 nsContentUtils::GetTextEditorFromAnonymousNodeWithoutCreation(
2658 eventContent);
2659 if (!textEditor || !textEditor->IsCopyToClipboardAllowed()) {
2660 StopTrackingDragGesture(true);
2661 return;
2662 }
2663 }
2664 DetermineDragTargetAndDefaultData(
2665 window, eventContent, dataTransfer, &allowEmptyDataTransfer,
2666 getter_AddRefs(selection), getter_AddRefs(remoteDragStartData),
2667 getter_AddRefs(targetContent), getter_AddRefs(principal),
2668 getter_AddRefs(csp), getter_AddRefs(cookieJarSettings));
2669 }
2670
2671 // Stop tracking the drag gesture now. This should stop us from
2672 // reentering GenerateDragGesture inside DOM event processing.
2673 // Pass false to avoid clearing the child process state since a real
2674 // drag should be starting.
2675 StopTrackingDragGesture(false);
2676
2677 if (!targetContent) return;
2678
2679 // Use our targetContent, now that we've determined it, as the
2680 // parent object of the DataTransfer.
2681 nsCOMPtr<nsIContent> parentContent =
2682 targetContent->FindFirstNonChromeOnlyAccessContent();
2683 dataTransfer->SetParentObject(parentContent);
2684
2685 sLastDragOverFrame = nullptr;
2686 nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget();
2687
2688 // get the widget from the target frame
2689 WidgetDragEvent startEvent(aEvent->IsTrusted(), eDragStart, widget);
2690 startEvent.mFlags.mIsSynthesizedForTests =
2691 aEvent->mFlags.mIsSynthesizedForTests;
2692 FillInEventFromGestureDown(&startEvent);
2693
2694 startEvent.mDataTransfer = dataTransfer;
2695 if (aEvent->AsMouseEvent()) {
2696 startEvent.mInputSource = aEvent->AsMouseEvent()->mInputSource;
2697 } else if (aEvent->AsTouchEvent()) {
2698 startEvent.mInputSource = MouseEvent_Binding::MOZ_SOURCE_TOUCH;
2699 } else {
2700 MOZ_ASSERT(false)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2700); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ")")
; do { *((volatile int*)__null) = 2700; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2701 }
2702
2703 // Dispatch to the DOM. By setting mCurrentTarget we are faking
2704 // out the ESM and telling it that the current target frame is
2705 // actually where the mouseDown occurred, otherwise it will use
2706 // the frame the mouse is currently over which may or may not be
2707 // the same.
2708
2709 // Hold onto old target content through the event and reset after.
2710 nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
2711
2712 // Set the current target to the content for the mouse down
2713 mCurrentTargetContent = targetContent;
2714
2715 // Dispatch the dragstart event to the DOM.
2716 nsEventStatus status = nsEventStatus_eIgnore;
2717 EventDispatcher::Dispatch(targetContent, aPresContext, &startEvent, nullptr,
2718 &status);
2719
2720 WidgetDragEvent* event = &startEvent;
2721
2722 nsCOMPtr<nsIObserverService> observerService =
2723 mozilla::services::GetObserverService();
2724 // Emit observer event to allow addons to modify the DataTransfer
2725 // object.
2726 if (observerService) {
2727 observerService->NotifyObservers(dataTransfer, "on-datatransfer-available",
2728 nullptr);
2729 }
2730
2731 if (status != nsEventStatus_eConsumeNoDefault) {
2732 bool dragStarted = DoDefaultDragStart(aPresContext, event, dataTransfer,
2733 allowEmptyDataTransfer, targetContent,
2734 selection, remoteDragStartData,
2735 principal, csp, cookieJarSettings);
2736 if (dragStarted) {
2737 sActiveESM = nullptr;
2738 MaybeFirePointerCancel(aEvent);
2739 aEvent->StopPropagation();
2740 }
2741 }
2742
2743 // Reset mCurretTargetContent to what it was
2744 mCurrentTargetContent = targetBeforeEvent;
2745
2746 // Now flush all pending notifications, for better responsiveness
2747 // while dragging.
2748 FlushLayout(aPresContext);
2749} // GenerateDragGesture
2750
2751void EventStateManager::DetermineDragTargetAndDefaultData(
2752 nsPIDOMWindowOuter* aWindow, nsIContent* aSelectionTarget,
2753 DataTransfer* aDataTransfer, bool* aAllowEmptyDataTransfer,
2754 Selection** aSelection, RemoteDragStartData** aRemoteDragStartData,
2755 nsIContent** aTargetNode, nsIPrincipal** aPrincipal,
2756 nsIContentSecurityPolicy** aCsp,
2757 nsICookieJarSettings** aCookieJarSettings) {
2758 *aTargetNode = nullptr;
2759 *aAllowEmptyDataTransfer = false;
2760 nsCOMPtr<nsIContent> dragDataNode;
2761
2762 nsIContent* editingElement = aSelectionTarget->IsEditable()
2763 ? aSelectionTarget->GetEditingHost()
2764 : nullptr;
2765
2766 // In chrome, only allow dragging inside editable areas.
2767 bool isChromeContext = !aWindow->GetBrowsingContext()->IsContent();
2768 if (isChromeContext && !editingElement) {
2769 if (mGestureDownDragStartData) {
2770 // A child process started a drag so use any data it assigned for the dnd
2771 // session.
2772 mGestureDownDragStartData->AddInitialDnDDataTo(aDataTransfer, aPrincipal,
2773 aCsp, aCookieJarSettings);
2774 mGestureDownDragStartData.forget(aRemoteDragStartData);
2775 *aAllowEmptyDataTransfer = true;
2776 }
2777 } else {
2778 mGestureDownDragStartData = nullptr;
2779
2780 // GetDragData determines if a selection, link or image in the content
2781 // should be dragged, and places the data associated with the drag in the
2782 // data transfer.
2783 // mGestureDownContent is the node where the mousedown event for the drag
2784 // occurred, and aSelectionTarget is the node to use when a selection is
2785 // used
2786 bool canDrag;
2787 bool wasAlt = (mGestureModifiers & MODIFIER_ALT) != 0;
2788 nsresult rv = nsContentAreaDragDrop::GetDragData(
2789 aWindow, mGestureDownContent, aSelectionTarget, wasAlt, aDataTransfer,
2790 &canDrag, aSelection, getter_AddRefs(dragDataNode), aCsp,
2791 aCookieJarSettings);
2792 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !canDrag) {
2793 return;
2794 }
2795 }
2796
2797 // if GetDragData returned a node, use that as the node being dragged.
2798 // Otherwise, if a selection is being dragged, use the node within the
2799 // selection that was dragged. Otherwise, just use the mousedown target.
2800 nsIContent* dragContent = mGestureDownContent;
2801 if (dragDataNode)
2802 dragContent = dragDataNode;
2803 else if (*aSelection)
2804 dragContent = aSelectionTarget;
2805
2806 nsIContent* originalDragContent = dragContent;
2807
2808 // If a selection isn't being dragged, look for an ancestor with the
2809 // draggable property set. If one is found, use that as the target of the
2810 // drag instead of the node that was clicked on. If a draggable node wasn't
2811 // found, just use the clicked node.
2812 if (!*aSelection) {
2813 while (dragContent) {
2814 if (auto htmlElement = nsGenericHTMLElement::FromNode(dragContent)) {
2815 if (htmlElement->Draggable()) {
2816 // We let draggable elements to trigger dnd even if there is no data
2817 // in the DataTransfer.
2818 *aAllowEmptyDataTransfer = true;
2819 break;
2820 }
2821 } else {
2822 if (dragContent->IsXULElement()) {
2823 // All XUL elements are draggable, so if a XUL element is
2824 // encountered, stop looking for draggable nodes and just use the
2825 // original clicked node instead.
2826 // XXXndeakin
2827 // In the future, we will want to improve this so that XUL has a
2828 // better way to specify whether something is draggable than just
2829 // on/off.
2830 dragContent = mGestureDownContent;
2831 break;
2832 }
2833 // otherwise, it's not an HTML or XUL element, so just keep looking
2834 }
2835 dragContent = dragContent->GetFlattenedTreeParent();
2836 }
2837 }
2838
2839 // if no node in the hierarchy was found to drag, but the GetDragData method
2840 // returned a node, use that returned node. Otherwise, nothing is draggable.
2841 if (!dragContent && dragDataNode) dragContent = dragDataNode;
2842
2843 if (dragContent) {
2844 // if an ancestor node was used instead, clear the drag data
2845 // XXXndeakin rework this a bit. Find a way to just not call GetDragData if
2846 // we don't need to.
2847 if (dragContent != originalDragContent) aDataTransfer->ClearAll();
2848 *aTargetNode = dragContent;
2849 NS_ADDREF(*aTargetNode)(*aTargetNode)->AddRef();
2850 }
2851}
2852
2853bool EventStateManager::DoDefaultDragStart(
2854 nsPresContext* aPresContext, WidgetDragEvent* aDragEvent,
2855 DataTransfer* aDataTransfer, bool aAllowEmptyDataTransfer,
2856 nsIContent* aDragTarget, Selection* aSelection,
2857 RemoteDragStartData* aDragStartData, nsIPrincipal* aPrincipal,
2858 nsIContentSecurityPolicy* aCsp, nsICookieJarSettings* aCookieJarSettings) {
2859 nsCOMPtr<nsIDragService> dragService =
2860 do_GetService("@mozilla.org/widget/dragservice;1");
2861 if (!dragService) return false;
2862
2863 // Default handling for the dragstart event.
2864 //
2865 // First, check if a drag session already exists. This means that the drag
2866 // service was called directly within a draggesture handler. In this case,
2867 // don't do anything more, as it is assumed that the handler is managing
2868 // drag and drop manually. Make sure to return true to indicate that a drag
2869 // began. However, if we're handling drag session for synthesized events,
2870 // we need to initialize some information of the session. Therefore, we
2871 // need to keep going for synthesized case.
2872 if (MOZ_UNLIKELY(!mPresContext)(__builtin_expect(!!(!mPresContext), 0))) {
2873 return true;
2874 }
2875 nsCOMPtr<nsIDragSession> dragSession =
2876 dragService->GetCurrentSession(mPresContext->GetRootWidget());
2877 if (dragSession && !dragSession->IsSynthesizedForTests()) {
2878 return true;
2879 }
2880
2881 // No drag session is currently active, so check if a handler added
2882 // any items to be dragged. If not, there isn't anything to drag.
2883 uint32_t count = 0;
2884 if (aDataTransfer) {
2885 count = aDataTransfer->MozItemCount();
2886 }
2887 if (!aAllowEmptyDataTransfer && !count) {
2888 return false;
2889 }
2890
2891 // Get the target being dragged, which may not be the same as the
2892 // target of the mouse event. If one wasn't set in the
2893 // aDataTransfer during the event handler, just use the original
2894 // target instead.
2895 nsCOMPtr<nsIContent> dragTarget = aDataTransfer->GetDragTarget();
2896 if (!dragTarget) {
2897 dragTarget = aDragTarget;
2898 if (!dragTarget) {
2899 return false;
2900 }
2901 }
2902
2903 // check which drag effect should initially be used. If the effect was not
2904 // set, just use all actions, otherwise Windows won't allow a drop.
2905 uint32_t action = aDataTransfer->EffectAllowedInt();
2906 if (action == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED) {
2907 action = nsIDragService::DRAGDROP_ACTION_COPY |
2908 nsIDragService::DRAGDROP_ACTION_MOVE |
2909 nsIDragService::DRAGDROP_ACTION_LINK;
2910 }
2911
2912 // get any custom drag image that was set
2913 int32_t imageX, imageY;
2914 RefPtr<Element> dragImage = aDataTransfer->GetDragImage(&imageX, &imageY);
2915
2916 nsCOMPtr<nsIArray> transArray = aDataTransfer->GetTransferables(dragTarget);
2917 if (!transArray) {
2918 return false;
2919 }
2920
2921 RefPtr<DataTransfer> dataTransfer;
2922 if (!dragSession) {
2923 // After this function returns, the DataTransfer will be cleared so it
2924 // appears empty to content. We need to pass a DataTransfer into the Drag
2925 // Session, so we need to make a copy.
2926 aDataTransfer->Clone(aDragTarget, eDrop, aDataTransfer->MozUserCancelled(),
2927 false, getter_AddRefs(dataTransfer));
2928
2929 // Copy over the drop effect, as Clone doesn't copy it for us.
2930 dataTransfer->SetDropEffectInt(aDataTransfer->DropEffectInt());
2931 } else {
2932 MOZ_ASSERT(dragSession->IsSynthesizedForTests())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(dragSession->IsSynthesizedForTests())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(dragSession->IsSynthesizedForTests()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("dragSession->IsSynthesizedForTests()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2932); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dragSession->IsSynthesizedForTests()"
")"); do { *((volatile int*)__null) = 2932; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2933 MOZ_ASSERT(aDragEvent->mFlags.mIsSynthesizedForTests)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDragEvent->mFlags.mIsSynthesizedForTests)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aDragEvent->mFlags.mIsSynthesizedForTests))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aDragEvent->mFlags.mIsSynthesizedForTests"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2933); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDragEvent->mFlags.mIsSynthesizedForTests"
")"); do { *((volatile int*)__null) = 2933; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2934 // If we're initializing synthesized drag session, we should use given
2935 // DataTransfer as is because it'll be used with following drag events
2936 // in any tests, therefore it should be set to nsIDragSession.dataTransfer
2937 // because it and DragEvent.dataTransfer should be same instance.
2938 dataTransfer = aDataTransfer;
2939 }
2940
2941 // XXXndeakin don't really want to create a new drag DOM event
2942 // here, but we need something to pass to the InvokeDragSession
2943 // methods.
2944 RefPtr<DragEvent> event =
2945 NS_NewDOMDragEvent(dragTarget, aPresContext, aDragEvent);
2946
2947 // Use InvokeDragSessionWithSelection if a selection is being dragged,
2948 // such that the image can be generated from the selected text. However,
2949 // use InvokeDragSessionWithImage if a custom image was set or something
2950 // other than a selection is being dragged.
2951 if (!dragImage && aSelection) {
2952 dragService->InvokeDragSessionWithSelection(
2953 aSelection, aPrincipal, aCsp, aCookieJarSettings, transArray, action,
2954 event, dataTransfer, dragTarget);
2955 } else if (aDragStartData) {
2956 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2956); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 2956; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2957 dragService->InvokeDragSessionWithRemoteImage(
2958 dragTarget, aPrincipal, aCsp, aCookieJarSettings, transArray, action,
2959 aDragStartData, event, dataTransfer);
2960 } else {
2961 dragService->InvokeDragSessionWithImage(
2962 dragTarget, aPrincipal, aCsp, aCookieJarSettings, transArray, action,
2963 dragImage, imageX, imageY, event, dataTransfer);
2964 }
2965
2966 return true;
2967}
2968
2969void EventStateManager::ChangeZoom(bool aIncrease) {
2970 // Send the zoom change to the top level browser so it will be handled by the
2971 // front end in the same way as other zoom actions.
2972 nsIDocShell* docShell = mDocument->GetDocShell();
2973 if (!docShell) {
2974 return;
2975 }
2976
2977 BrowsingContext* bc = docShell->GetBrowsingContext();
2978 if (!bc) {
2979 return;
2980 }
2981
2982 if (XRE_IsParentProcess()) {
2983 bc->Canonical()->DispatchWheelZoomChange(aIncrease);
2984 } else if (BrowserChild* child = BrowserChild::GetFrom(docShell)) {
2985 child->SendWheelZoomChange(aIncrease);
2986 }
2987}
2988
2989void EventStateManager::DoScrollHistory(int32_t direction) {
2990 nsCOMPtr<nsISupports> pcContainer(mPresContext->GetContainerWeak());
2991 if (pcContainer) {
2992 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(pcContainer));
2993 if (webNav) {
2994 // positive direction to go back one step, nonpositive to go forward
2995 // This is doing user-initiated history traversal, hence we want
2996 // to require that history entries we navigate to have user interaction.
2997 if (direction > 0)
2998 webNav->GoBack(StaticPrefs::browser_navigation_requireUserInteraction(),
2999 true);
3000 else
3001 webNav->GoForward(
3002 StaticPrefs::browser_navigation_requireUserInteraction(), true);
3003 }
3004 }
3005}
3006
3007void EventStateManager::DoScrollZoom(nsIFrame* aTargetFrame,
3008 int32_t adjustment) {
3009 // Exclude content in chrome docshells.
3010 nsIContent* content = aTargetFrame->GetContent();
3011 if (content && !nsContentUtils::IsInChromeDocshell(content->OwnerDoc())) {
3012 // Positive adjustment to decrease zoom, negative to increase
3013 const bool increase = adjustment <= 0;
3014 EnsureDocument(mPresContext);
3015 ChangeZoom(increase);
3016 }
3017}
3018
3019static nsIFrame* GetParentFrameToScroll(nsIFrame* aFrame) {
3020 if (!aFrame) return nullptr;
3021
3022 if (aFrame->StyleDisplay()->mPosition == StylePositionProperty::Fixed &&
3023 nsLayoutUtils::IsReallyFixedPos(aFrame)) {
3024 return aFrame->PresShell()->GetRootScrollContainerFrame();
3025 }
3026 return aFrame->GetParent();
3027}
3028
3029void EventStateManager::DispatchLegacyMouseScrollEvents(
3030 nsIFrame* aTargetFrame, WidgetWheelEvent* aEvent, nsEventStatus* aStatus) {
3031 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3031); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 3031; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3032 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3032); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 3032; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3033
3034 if (!aTargetFrame || *aStatus == nsEventStatus_eConsumeNoDefault) {
3035 return;
3036 }
3037
3038 // Ignore mouse wheel transaction for computing legacy mouse wheel
3039 // events' delta value.
3040 // DOM event's delta vales are computed from CSS pixels.
3041 auto scrollAmountInCSSPixels =
3042 CSSIntSize::FromAppUnitsRounded(aEvent->mScrollAmount);
3043
3044 // XXX We don't deal with fractional amount in legacy event, though the
3045 // default action handler (DoScrollText()) deals with it.
3046 // If we implemented such strict computation, we would need additional
3047 // accumulated delta values. It would made the code more complicated.
3048 // And also it would computes different delta values from older version.
3049 // It doesn't make sense to implement such code for legacy events and
3050 // rare cases.
3051 int32_t scrollDeltaX, scrollDeltaY, pixelDeltaX, pixelDeltaY;
3052 switch (aEvent->mDeltaMode) {
3053 case WheelEvent_Binding::DOM_DELTA_PAGE:
3054 scrollDeltaX = !aEvent->mLineOrPageDeltaX
3055 ? 0
3056 : (aEvent->mLineOrPageDeltaX > 0
3057 ? UIEvent_Binding::SCROLL_PAGE_DOWN
3058 : UIEvent_Binding::SCROLL_PAGE_UP);
3059 scrollDeltaY = !aEvent->mLineOrPageDeltaY
3060 ? 0
3061 : (aEvent->mLineOrPageDeltaY > 0
3062 ? UIEvent_Binding::SCROLL_PAGE_DOWN
3063 : UIEvent_Binding::SCROLL_PAGE_UP);
3064 pixelDeltaX = RoundDown(aEvent->mDeltaX * scrollAmountInCSSPixels.width);
3065 pixelDeltaY = RoundDown(aEvent->mDeltaY * scrollAmountInCSSPixels.height);
3066 break;
3067
3068 case WheelEvent_Binding::DOM_DELTA_LINE:
3069 scrollDeltaX = aEvent->mLineOrPageDeltaX;
3070 scrollDeltaY = aEvent->mLineOrPageDeltaY;
3071 pixelDeltaX = RoundDown(aEvent->mDeltaX * scrollAmountInCSSPixels.width);
3072 pixelDeltaY = RoundDown(aEvent->mDeltaY * scrollAmountInCSSPixels.height);
3073 break;
3074
3075 case WheelEvent_Binding::DOM_DELTA_PIXEL:
3076 scrollDeltaX = aEvent->mLineOrPageDeltaX;
3077 scrollDeltaY = aEvent->mLineOrPageDeltaY;
3078 pixelDeltaX = RoundDown(aEvent->mDeltaX);
3079 pixelDeltaY = RoundDown(aEvent->mDeltaY);
3080 break;
3081
3082 default:
3083 MOZ_CRASH("Invalid deltaMode value comes")do { do { } while (false); MOZ_ReportCrash("" "Invalid deltaMode value comes"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3083); AnnotateMozCrashReason("MOZ_CRASH(" "Invalid deltaMode value comes"
")"); do { *((volatile int*)__null) = 3083; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
3084 }
3085
3086 // Send the legacy events in following order:
3087 // 1. Vertical scroll
3088 // 2. Vertical pixel scroll (even if #1 isn't consumed)
3089 // 3. Horizontal scroll (even if #1 and/or #2 are consumed)
3090 // 4. Horizontal pixel scroll (even if #3 isn't consumed)
3091
3092 AutoWeakFrame targetFrame(aTargetFrame);
3093
3094 MOZ_ASSERT(*aStatus != nsEventStatus_eConsumeNoDefault &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault &&
!aEvent->DefaultPrevented())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aStatus != nsEventStatus_eConsumeNoDefault
&& !aEvent->DefaultPrevented()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
" (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3097); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
") (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")"); do {
*((volatile int*)__null) = 3097; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3095 !aEvent->DefaultPrevented(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault &&
!aEvent->DefaultPrevented())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aStatus != nsEventStatus_eConsumeNoDefault
&& !aEvent->DefaultPrevented()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
" (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3097); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
") (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")"); do {
*((volatile int*)__null) = 3097; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3096 "If you make legacy events dispatched for default prevented wheel "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault &&
!aEvent->DefaultPrevented())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aStatus != nsEventStatus_eConsumeNoDefault
&& !aEvent->DefaultPrevented()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
" (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3097); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
") (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")"); do {
*((volatile int*)__null) = 3097; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3097 "event, you need to initialize stateX and stateY")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault &&
!aEvent->DefaultPrevented())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aStatus != nsEventStatus_eConsumeNoDefault
&& !aEvent->DefaultPrevented()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
" (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3097); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
") (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")"); do {
*((volatile int*)__null) = 3097; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
3098 EventState stateX, stateY;
3099 if (scrollDeltaY) {
3100 SendLineScrollEvent(aTargetFrame, aEvent, stateY, scrollDeltaY,
3101 DELTA_DIRECTION_Y);
3102 if (!targetFrame.IsAlive()) {
3103 *aStatus = nsEventStatus_eConsumeNoDefault;
3104 return;
3105 }
3106 }
3107
3108 if (pixelDeltaY) {
3109 SendPixelScrollEvent(aTargetFrame, aEvent, stateY, pixelDeltaY,
3110 DELTA_DIRECTION_Y);
3111 if (!targetFrame.IsAlive()) {
3112 *aStatus = nsEventStatus_eConsumeNoDefault;
3113 return;
3114 }
3115 }
3116
3117 if (scrollDeltaX) {
3118 SendLineScrollEvent(aTargetFrame, aEvent, stateX, scrollDeltaX,
3119 DELTA_DIRECTION_X);
3120 if (!targetFrame.IsAlive()) {
3121 *aStatus = nsEventStatus_eConsumeNoDefault;
3122 return;
3123 }
3124 }
3125
3126 if (pixelDeltaX) {
3127 SendPixelScrollEvent(aTargetFrame, aEvent, stateX, pixelDeltaX,
3128 DELTA_DIRECTION_X);
3129 if (!targetFrame.IsAlive()) {
3130 *aStatus = nsEventStatus_eConsumeNoDefault;
3131 return;
3132 }
3133 }
3134
3135 if (stateY.mDefaultPrevented) {
3136 *aStatus = nsEventStatus_eConsumeNoDefault;
3137 aEvent->PreventDefault(!stateY.mDefaultPreventedByContent);
3138 }
3139
3140 if (stateX.mDefaultPrevented) {
3141 *aStatus = nsEventStatus_eConsumeNoDefault;
3142 aEvent->PreventDefault(!stateX.mDefaultPreventedByContent);
3143 }
3144}
3145
3146void EventStateManager::SendLineScrollEvent(nsIFrame* aTargetFrame,
3147 WidgetWheelEvent* aEvent,
3148 EventState& aState, int32_t aDelta,
3149 DeltaDirection aDeltaDirection) {
3150 nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
3151 if (!targetContent) {
3152 targetContent = GetFocusedElement();
3153 if (!targetContent) {
3154 return;
3155 }
3156 }
3157
3158 while (targetContent->IsText()) {
3159 targetContent = targetContent->GetFlattenedTreeParent();
3160 }
3161
3162 WidgetMouseScrollEvent event(aEvent->IsTrusted(),
3163 eLegacyMouseLineOrPageScroll, aEvent->mWidget);
3164 event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
3165 event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
3166 event.mRefPoint = aEvent->mRefPoint;
3167 event.mTimeStamp = aEvent->mTimeStamp;
3168 event.mModifiers = aEvent->mModifiers;
3169 event.mButtons = aEvent->mButtons;
3170 event.mIsHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
3171 event.mDelta = aDelta;
3172 event.mInputSource = aEvent->mInputSource;
3173
3174 RefPtr<nsPresContext> presContext = aTargetFrame->PresContext();
3175 nsEventStatus status = nsEventStatus_eIgnore;
3176 EventDispatcher::Dispatch(targetContent, presContext, &event, nullptr,
3177 &status);
3178 aState.mDefaultPrevented =
3179 event.DefaultPrevented() || status == nsEventStatus_eConsumeNoDefault;
3180 aState.mDefaultPreventedByContent = event.DefaultPreventedByContent();
3181}
3182
3183void EventStateManager::SendPixelScrollEvent(nsIFrame* aTargetFrame,
3184 WidgetWheelEvent* aEvent,
3185 EventState& aState,
3186 int32_t aPixelDelta,
3187 DeltaDirection aDeltaDirection) {
3188 nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
3189 if (!targetContent) {
3190 targetContent = GetFocusedElement();
3191 if (!targetContent) {
3192 return;
3193 }
3194 }
3195
3196 while (targetContent->IsText()) {
3197 targetContent = targetContent->GetFlattenedTreeParent();
3198 }
3199
3200 WidgetMouseScrollEvent event(aEvent->IsTrusted(), eLegacyMousePixelScroll,
3201 aEvent->mWidget);
3202 event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
3203 event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
3204 event.mRefPoint = aEvent->mRefPoint;
3205 event.mTimeStamp = aEvent->mTimeStamp;
3206 event.mModifiers = aEvent->mModifiers;
3207 event.mButtons = aEvent->mButtons;
3208 event.mIsHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
3209 event.mDelta = aPixelDelta;
3210 event.mInputSource = aEvent->mInputSource;
3211
3212 RefPtr<nsPresContext> presContext = aTargetFrame->PresContext();
3213 nsEventStatus status = nsEventStatus_eIgnore;
3214 EventDispatcher::Dispatch(targetContent, presContext, &event, nullptr,
3215 &status);
3216 aState.mDefaultPrevented =
3217 event.DefaultPrevented() || status == nsEventStatus_eConsumeNoDefault;
3218 aState.mDefaultPreventedByContent = event.DefaultPreventedByContent();
3219}
3220
3221ScrollContainerFrame*
3222EventStateManager::ComputeScrollTargetAndMayAdjustWheelEvent(
3223 nsIFrame* aTargetFrame, WidgetWheelEvent* aEvent,
3224 ComputeScrollTargetOptions aOptions) {
3225 return ComputeScrollTargetAndMayAdjustWheelEvent(
18
Calling 'EventStateManager::ComputeScrollTargetAndMayAdjustWheelEvent'
3226 aTargetFrame, aEvent->mDeltaX, aEvent->mDeltaY, aEvent, aOptions);
17
Passing value via 1st parameter 'aTargetFrame'
3227}
3228
3229// Overload ComputeScrollTargetAndMayAdjustWheelEvent method to allow passing
3230// "test" dx and dy when looking for which scrollbarmediators to activate when
3231// two finger down on trackpad and before any actual motion
3232ScrollContainerFrame*
3233EventStateManager::ComputeScrollTargetAndMayAdjustWheelEvent(
3234 nsIFrame* aTargetFrame, double aDirectionX, double aDirectionY,
3235 WidgetWheelEvent* aEvent, ComputeScrollTargetOptions aOptions) {
3236 bool isAutoDir = false;
3237 bool honoursRoot = false;
3238 if (MAY_BE_ADJUSTED_BY_AUTO_DIR & aOptions) {
19
Taking false branch
3239 // If the scroll is respected as auto-dir, aDirection* should always be
3240 // equivalent to the event's delta vlaues(Currently, there are only one case
3241 // where aDirection*s have different values from the widget wheel event's
3242 // original delta values and the only case isn't auto-dir, see
3243 // ScrollbarsForWheel::TemporarilyActivateAllPossibleScrollTargets).
3244 MOZ_ASSERT(aDirectionX == aEvent->mDeltaX &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDirectionX == aEvent->mDeltaX && aDirectionY
== aEvent->mDeltaY)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDirectionX == aEvent->mDeltaX
&& aDirectionY == aEvent->mDeltaY))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aDirectionX == aEvent->mDeltaX && aDirectionY == aEvent->mDeltaY"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3245); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDirectionX == aEvent->mDeltaX && aDirectionY == aEvent->mDeltaY"
")"); do { *((volatile int*)__null) = 3245; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3245 aDirectionY == aEvent->mDeltaY)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDirectionX == aEvent->mDeltaX && aDirectionY
== aEvent->mDeltaY)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDirectionX == aEvent->mDeltaX
&& aDirectionY == aEvent->mDeltaY))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aDirectionX == aEvent->mDeltaX && aDirectionY == aEvent->mDeltaY"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3245); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDirectionX == aEvent->mDeltaX && aDirectionY == aEvent->mDeltaY"
")"); do { *((volatile int*)__null) = 3245; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3246
3247 WheelDeltaAdjustmentStrategy strategy =
3248 GetWheelDeltaAdjustmentStrategy(*aEvent);
3249 switch (strategy) {
3250 case WheelDeltaAdjustmentStrategy::eAutoDir:
3251 isAutoDir = true;
3252 honoursRoot = false;
3253 break;
3254 case WheelDeltaAdjustmentStrategy::eAutoDirWithRootHonour:
3255 isAutoDir = true;
3256 honoursRoot = true;
3257 break;
3258 default:
3259 break;
3260 }
3261 }
3262
3263 if (aOptions & PREFER_MOUSE_WHEEL_TRANSACTION) {
20
Taking true branch
3264 // If the user recently scrolled with the mousewheel, then they probably
3265 // want to scroll the same view as before instead of the view under the
3266 // cursor. WheelTransaction tracks the frame currently being
3267 // scrolled with the mousewheel. We consider the transaction ended when the
3268 // mouse moves more than "mousewheel.transaction.ignoremovedelay"
3269 // milliseconds after the last scroll operation, or any time the mouse moves
3270 // out of the frame, or when more than "mousewheel.transaction.timeout"
3271 // milliseconds have passed after the last operation, even if the mouse
3272 // hasn't moved.
3273 nsIFrame* lastScrollFrame = WheelTransaction::GetScrollTargetFrame();
3274 if (lastScrollFrame) {
21
Assuming 'lastScrollFrame' is null
3275 ScrollContainerFrame* scrollContainerFrame =
3276 lastScrollFrame->GetScrollTargetFrame();
3277 if (scrollContainerFrame) {
3278 if (isAutoDir) {
3279 ESMAutoDirWheelDeltaAdjuster adjuster(*aEvent, *lastScrollFrame,
3280 honoursRoot);
3281 // Note that calling this function will not always cause the delta to
3282 // be adjusted, it only adjusts the delta when it should, because
3283 // Adjust() internally calls ShouldBeAdjusted() before making
3284 // adjustment.
3285 adjuster.Adjust();
3286 }
3287 return scrollContainerFrame;
3288 }
3289 }
3290 }
3291
3292 // If the event doesn't cause scroll actually, we cannot find scroll target
3293 // because we check if the event can cause scroll actually on each found
3294 // scrollable frame.
3295 if (!aDirectionX && !aDirectionY) {
22
Assuming the condition is false
3296 return nullptr;
3297 }
3298
3299 bool checkIfScrollableX;
3300 bool checkIfScrollableY;
3301 if (isAutoDir
22.1
'isAutoDir' is false
22.1
'isAutoDir' is false
) {
3302 // Always check the frame's scrollability in both the two directions for an
3303 // auto-dir scroll. That is, for an auto-dir scroll,
3304 // PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS and
3305 // PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS should be ignored.
3306 checkIfScrollableX = true;
3307 checkIfScrollableY = true;
3308 } else {
3309 checkIfScrollableX =
3310 aDirectionX &&
23
Assuming the condition is false
3311 (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS);
3312 checkIfScrollableY =
3313 aDirectionY &&
24
Assuming the condition is false
3314 (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS);
3315 }
3316
3317 nsIFrame* scrollFrame = !(aOptions & START_FROM_PARENT)
25
'?' condition is true
3318 ? aTargetFrame
3319 : GetParentFrameToScroll(aTargetFrame);
3320 for (; scrollFrame; scrollFrame = GetParentFrameToScroll(scrollFrame)) {
26
Assuming pointer value is null
27
Loop condition is false. Execution continues on line 3394
3321 // Check whether the frame wants to provide us with a scrollable view.
3322 ScrollContainerFrame* scrollContainerFrame =
3323 scrollFrame->GetScrollTargetFrame();
3324 if (!scrollContainerFrame) {
3325 nsMenuPopupFrame* menuPopupFrame = do_QueryFrame(scrollFrame);
3326 if (menuPopupFrame) {
3327 return nullptr;
3328 }
3329 continue;
3330 }
3331
3332 if (!checkIfScrollableX && !checkIfScrollableY) {
3333 return scrollContainerFrame;
3334 }
3335
3336 // If the frame disregards the direction the user is trying to scroll, then
3337 // it should just bubbles the scroll event up to its parental scroll frame
3338
3339 Maybe<layers::ScrollDirection> disregardedDirection =
3340 WheelHandlingUtils::GetDisregardedWheelScrollDirection(scrollFrame);
3341 if (disregardedDirection) {
3342 switch (disregardedDirection.ref()) {
3343 case layers::ScrollDirection::eHorizontal:
3344 if (checkIfScrollableX) {
3345 continue;
3346 }
3347 break;
3348 case layers::ScrollDirection::eVertical:
3349 if (checkIfScrollableY) {
3350 continue;
3351 }
3352 break;
3353 }
3354 }
3355
3356 layers::ScrollDirections directions =
3357 scrollContainerFrame
3358 ->GetAvailableScrollingDirectionsForUserInputEvents();
3359 if ((!(directions.contains(layers::ScrollDirection::eVertical)) &&
3360 !(directions.contains(layers::ScrollDirection::eHorizontal))) ||
3361 (checkIfScrollableY && !checkIfScrollableX &&
3362 !(directions.contains(layers::ScrollDirection::eVertical))) ||
3363 (checkIfScrollableX && !checkIfScrollableY &&
3364 !(directions.contains(layers::ScrollDirection::eHorizontal)))) {
3365 continue;
3366 }
3367
3368 // Computes whether the currently checked frame is scrollable by this wheel
3369 // event.
3370 bool canScroll = false;
3371 if (isAutoDir) {
3372 ESMAutoDirWheelDeltaAdjuster adjuster(*aEvent, *scrollFrame, honoursRoot);
3373 if (adjuster.ShouldBeAdjusted()) {
3374 adjuster.Adjust();
3375 canScroll = true;
3376 } else if (WheelHandlingUtils::CanScrollOn(scrollContainerFrame,
3377 aDirectionX, aDirectionY)) {
3378 canScroll = true;
3379 }
3380 } else if (WheelHandlingUtils::CanScrollOn(scrollContainerFrame,
3381 aDirectionX, aDirectionY)) {
3382 canScroll = true;
3383 }
3384
3385 if (canScroll) {
3386 return scrollContainerFrame;
3387 }
3388
3389 // Where we are at is the block ending in a for loop.
3390 // The current frame has been checked to be unscrollable by this wheel
3391 // event, continue the loop to check its parent, if any.
3392 }
3393
3394 nsIFrame* newFrame = nsLayoutUtils::GetCrossDocParentFrameInProcess(
3395 aTargetFrame->PresShell()->GetRootFrame());
28
Called C++ object pointer is null
3396 aOptions =
3397 static_cast<ComputeScrollTargetOptions>(aOptions & ~START_FROM_PARENT);
3398 if (!newFrame) {
3399 return nullptr;
3400 }
3401 return ComputeScrollTargetAndMayAdjustWheelEvent(newFrame, aEvent, aOptions);
3402}
3403
3404nsSize EventStateManager::GetScrollAmount(
3405 nsPresContext* aPresContext, WidgetWheelEvent* aEvent,
3406 ScrollContainerFrame* aScrollContainerFrame) {
3407 MOZ_ASSERT(aPresContext)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresContext))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPresContext", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3407); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresContext"
")"); do { *((volatile int*)__null) = 3407; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3408 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3408); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 3408; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3409
3410 const bool isPage = aEvent->mDeltaMode == WheelEvent_Binding::DOM_DELTA_PAGE;
3411 if (!aScrollContainerFrame) {
3412 // If there is no scrollable frame, we should use root, see below.
3413 aScrollContainerFrame =
3414 aPresContext->PresShell()->GetRootScrollContainerFrame();
3415 }
3416
3417 if (aScrollContainerFrame) {
3418 return isPage ? aScrollContainerFrame->GetPageScrollAmount()
3419 : aScrollContainerFrame->GetLineScrollAmount();
3420 }
3421
3422 // If there is no scrollable frame and page scrolling, use viewport size.
3423 if (isPage) {
3424 return aPresContext->GetVisibleArea().Size();
3425 }
3426
3427 // Otherwise use root frame's font metrics.
3428 //
3429 // FIXME(emilio): Should this use the root element's style frame? The root
3430 // frame will always have the initial font. Then again it should never matter
3431 // for content, we should always have a root scrollable frame in html
3432 // documents.
3433 nsIFrame* rootFrame = aPresContext->PresShell()->GetRootFrame();
3434 if (!rootFrame) {
3435 return nsSize(0, 0);
3436 }
3437 RefPtr<nsFontMetrics> fm =
3438 nsLayoutUtils::GetInflatedFontMetricsForFrame(rootFrame);
3439 NS_ENSURE_TRUE(fm, nsSize(0, 0))do { if ((__builtin_expect(!!(!(fm)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "fm" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3439); return nsSize(0, 0); } } while (false)
;
3440 return nsSize(fm->AveCharWidth(), fm->MaxHeight());
3441}
3442
3443void EventStateManager::DoScrollText(
3444 ScrollContainerFrame* aScrollContainerFrame, WidgetWheelEvent* aEvent) {
3445 MOZ_ASSERT(aScrollContainerFrame)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aScrollContainerFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aScrollContainerFrame))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aScrollContainerFrame"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3445); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aScrollContainerFrame"
")"); do { *((volatile int*)__null) = 3445; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3446 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3446); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 3446; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3447
3448 AutoWeakFrame scrollFrameWeak(aScrollContainerFrame);
3449 AutoWeakFrame eventFrameWeak(mCurrentTarget);
3450 if (!WheelTransaction::WillHandleDefaultAction(aEvent, scrollFrameWeak,
3451 eventFrameWeak)) {
3452 return;
3453 }
3454
3455 // Default action's actual scroll amount should be computed from device
3456 // pixels.
3457 nsPresContext* pc = aScrollContainerFrame->PresContext();
3458 nsSize scrollAmount = GetScrollAmount(pc, aEvent, aScrollContainerFrame);
3459 nsIntSize scrollAmountInDevPixels(
3460 pc->AppUnitsToDevPixels(scrollAmount.width),
3461 pc->AppUnitsToDevPixels(scrollAmount.height));
3462 nsIntPoint actualDevPixelScrollAmount =
3463 DeltaAccumulator::GetInstance()->ComputeScrollAmountForDefaultAction(
3464 aEvent, scrollAmountInDevPixels);
3465
3466 // Don't scroll around the axis whose overflow style is hidden.
3467 ScrollStyles overflowStyle = aScrollContainerFrame->GetScrollStyles();
3468 if (overflowStyle.mHorizontal == StyleOverflow::Hidden) {
3469 actualDevPixelScrollAmount.x = 0;
3470 }
3471 if (overflowStyle.mVertical == StyleOverflow::Hidden) {
3472 actualDevPixelScrollAmount.y = 0;
3473 }
3474
3475 ScrollSnapFlags snapFlags = ScrollSnapFlags::Disabled;
3476 mozilla::ScrollOrigin origin = mozilla::ScrollOrigin::NotSpecified;
3477 switch (aEvent->mDeltaMode) {
3478 case WheelEvent_Binding::DOM_DELTA_LINE:
3479 origin = mozilla::ScrollOrigin::MouseWheel;
3480 snapFlags = ScrollSnapFlags::IntendedDirection;
3481 break;
3482 case WheelEvent_Binding::DOM_DELTA_PAGE:
3483 origin = mozilla::ScrollOrigin::Pages;
3484 snapFlags = ScrollSnapFlags::IntendedDirection |
3485 ScrollSnapFlags::IntendedEndPosition;
3486 break;
3487 case WheelEvent_Binding::DOM_DELTA_PIXEL:
3488 origin = mozilla::ScrollOrigin::Pixels;
3489 break;
3490 default:
3491 MOZ_CRASH("Invalid deltaMode value comes")do { do { } while (false); MOZ_ReportCrash("" "Invalid deltaMode value comes"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3491); AnnotateMozCrashReason("MOZ_CRASH(" "Invalid deltaMode value comes"
")"); do { *((volatile int*)__null) = 3491; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
3492 }
3493
3494 // We shouldn't scroll more one page at once except when over one page scroll
3495 // is allowed for the event.
3496 nsSize pageSize = aScrollContainerFrame->GetPageScrollAmount();
3497 nsIntSize devPixelPageSize(pc->AppUnitsToDevPixels(pageSize.width),
3498 pc->AppUnitsToDevPixels(pageSize.height));
3499 if (!WheelPrefs::GetInstance()->IsOverOnePageScrollAllowedX(aEvent) &&
3500 DeprecatedAbs(actualDevPixelScrollAmount.x.value) >
3501 devPixelPageSize.width) {
3502 actualDevPixelScrollAmount.x = (actualDevPixelScrollAmount.x >= 0)
3503 ? devPixelPageSize.width
3504 : -devPixelPageSize.width;
3505 }
3506
3507 if (!WheelPrefs::GetInstance()->IsOverOnePageScrollAllowedY(aEvent) &&
3508 DeprecatedAbs(actualDevPixelScrollAmount.y.value) >
3509 devPixelPageSize.height) {
3510 actualDevPixelScrollAmount.y = (actualDevPixelScrollAmount.y >= 0)
3511 ? devPixelPageSize.height
3512 : -devPixelPageSize.height;
3513 }
3514
3515 bool isDeltaModePixel =
3516 (aEvent->mDeltaMode == WheelEvent_Binding::DOM_DELTA_PIXEL);
3517
3518 ScrollMode mode;
3519 switch (aEvent->mScrollType) {
3520 case WidgetWheelEvent::SCROLL_DEFAULT:
3521 if (isDeltaModePixel) {
3522 mode = ScrollMode::Normal;
3523 } else if (aEvent->mFlags.mHandledByAPZ) {
3524 mode = ScrollMode::SmoothMsd;
3525 } else {
3526 mode = ScrollMode::Smooth;
3527 }
3528 break;
3529 case WidgetWheelEvent::SCROLL_SYNCHRONOUSLY:
3530 mode = ScrollMode::Instant;
3531 break;
3532 case WidgetWheelEvent::SCROLL_ASYNCHRONOUSLY:
3533 mode = ScrollMode::Normal;
3534 break;
3535 case WidgetWheelEvent::SCROLL_SMOOTHLY:
3536 mode = ScrollMode::Smooth;
3537 break;
3538 default:
3539 MOZ_CRASH("Invalid mScrollType value comes")do { do { } while (false); MOZ_ReportCrash("" "Invalid mScrollType value comes"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3539); AnnotateMozCrashReason("MOZ_CRASH(" "Invalid mScrollType value comes"
")"); do { *((volatile int*)__null) = 3539; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
3540 }
3541
3542 ScrollContainerFrame::ScrollMomentum momentum =
3543 aEvent->mIsMomentum ? ScrollContainerFrame::SYNTHESIZED_MOMENTUM_EVENT
3544 : ScrollContainerFrame::NOT_MOMENTUM;
3545
3546 nsIntPoint overflow;
3547 aScrollContainerFrame->ScrollBy(actualDevPixelScrollAmount,
3548 ScrollUnit::DEVICE_PIXELS, mode, &overflow,
3549 origin, momentum, snapFlags);
3550
3551 if (!scrollFrameWeak.IsAlive()) {
3552 // If the scroll causes changing the layout, we can think that the event
3553 // has been completely consumed by the content. Then, users probably don't
3554 // want additional action.
3555 aEvent->mOverflowDeltaX = aEvent->mOverflowDeltaY = 0;
3556 } else if (isDeltaModePixel) {
3557 aEvent->mOverflowDeltaX = overflow.x;
3558 aEvent->mOverflowDeltaY = overflow.y;
3559 } else {
3560 aEvent->mOverflowDeltaX =
3561 static_cast<double>(overflow.x) / scrollAmountInDevPixels.width;
3562 aEvent->mOverflowDeltaY =
3563 static_cast<double>(overflow.y) / scrollAmountInDevPixels.height;
3564 }
3565
3566 // If CSS overflow properties caused not to scroll, the overflowDelta* values
3567 // should be same as delta* values since they may be used as gesture event by
3568 // widget. However, if there is another scrollable element in the ancestor
3569 // along the axis, probably users don't want the operation to cause
3570 // additional action such as moving history. In such case, overflowDelta
3571 // values should stay zero.
3572 if (scrollFrameWeak.IsAlive()) {
3573 if (aEvent->mDeltaX && overflowStyle.mHorizontal == StyleOverflow::Hidden &&
3574 !ComputeScrollTargetAndMayAdjustWheelEvent(
3575 aScrollContainerFrame, aEvent,
3576 COMPUTE_SCROLLABLE_ANCESTOR_ALONG_X_AXIS_WITH_AUTO_DIR)) {
3577 aEvent->mOverflowDeltaX = aEvent->mDeltaX;
3578 }
3579 if (aEvent->mDeltaY && overflowStyle.mVertical == StyleOverflow::Hidden &&
3580 !ComputeScrollTargetAndMayAdjustWheelEvent(
3581 aScrollContainerFrame, aEvent,
3582 COMPUTE_SCROLLABLE_ANCESTOR_ALONG_Y_AXIS_WITH_AUTO_DIR)) {
3583 aEvent->mOverflowDeltaY = aEvent->mDeltaY;
3584 }
3585 }
3586
3587 NS_ASSERTION(do { if (!(aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX
> 0) == (aEvent->mDeltaX > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaX is different from the scroll direction"
, "aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3590); MOZ_PretendNoReturn(); } } while (0)
3588 aEvent->mOverflowDeltaX == 0 ||do { if (!(aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX
> 0) == (aEvent->mDeltaX > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaX is different from the scroll direction"
, "aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3590); MOZ_PretendNoReturn(); } } while (0)
3589 (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0),do { if (!(aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX
> 0) == (aEvent->mDeltaX > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaX is different from the scroll direction"
, "aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3590); MOZ_PretendNoReturn(); } } while (0)
3590 "The sign of mOverflowDeltaX is different from the scroll direction")do { if (!(aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX
> 0) == (aEvent->mDeltaX > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaX is different from the scroll direction"
, "aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3590); MOZ_PretendNoReturn(); } } while (0)
;
3591 NS_ASSERTION(do { if (!(aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY
> 0) == (aEvent->mDeltaY > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaY is different from the scroll direction"
, "aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3594); MOZ_PretendNoReturn(); } } while (0)
3592 aEvent->mOverflowDeltaY == 0 ||do { if (!(aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY
> 0) == (aEvent->mDeltaY > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaY is different from the scroll direction"
, "aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3594); MOZ_PretendNoReturn(); } } while (0)
3593 (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0),do { if (!(aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY
> 0) == (aEvent->mDeltaY > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaY is different from the scroll direction"
, "aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3594); MOZ_PretendNoReturn(); } } while (0)
3594 "The sign of mOverflowDeltaY is different from the scroll direction")do { if (!(aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY
> 0) == (aEvent->mDeltaY > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaY is different from the scroll direction"
, "aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3594); MOZ_PretendNoReturn(); } } while (0)
;
3595
3596 WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(aEvent);
3597}
3598
3599void EventStateManager::DecideGestureEvent(WidgetGestureNotifyEvent* aEvent,
3600 nsIFrame* targetFrame) {
3601 NS_ASSERTION(aEvent->mMessage == eGestureNotify,do { if (!(aEvent->mMessage == eGestureNotify)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "DecideGestureEvent called with a non-gesture event"
, "aEvent->mMessage == eGestureNotify", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3602); MOZ_PretendNoReturn(); } } while (0)
3602 "DecideGestureEvent called with a non-gesture event")do { if (!(aEvent->mMessage == eGestureNotify)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "DecideGestureEvent called with a non-gesture event"
, "aEvent->mMessage == eGestureNotify", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3602); MOZ_PretendNoReturn(); } } while (0)
;
3603
3604 /* Check the ancestor tree to decide if any frame is willing* to receive
3605 * a MozPixelScroll event. If that's the case, the current touch gesture
3606 * will be used as a pan gesture; otherwise it will be a regular
3607 * mousedown/mousemove/click event.
3608 *
3609 * *willing: determine if it makes sense to pan the element using scroll
3610 * events:
3611 * - For web content: if there are any visible scrollbars on the touch point
3612 * - For XUL: if it's an scrollable element that can currently scroll in some
3613 * direction.
3614 *
3615 * Note: we'll have to one-off various cases to ensure a good usable behavior
3616 */
3617 WidgetGestureNotifyEvent::PanDirection panDirection =
3618 WidgetGestureNotifyEvent::ePanNone;
3619 bool displayPanFeedback = false;
3620 for (nsIFrame* current = targetFrame; current;
3621 current = nsLayoutUtils::GetCrossDocParentFrame(current)) {
3622 // e10s - mark remote content as pannable. This is a work around since
3623 // we don't have access to remote frame scroll info here. Apz data may
3624 // assist is solving this.
3625 if (current && IsTopLevelRemoteTarget(current->GetContent())) {
3626 panDirection = WidgetGestureNotifyEvent::ePanBoth;
3627 // We don't know when we reach bounds, so just disable feedback for now.
3628 displayPanFeedback = false;
3629 break;
3630 }
3631
3632 LayoutFrameType currentFrameType = current->Type();
3633
3634 // Scrollbars should always be draggable
3635 if (currentFrameType == LayoutFrameType::Scrollbar) {
3636 panDirection = WidgetGestureNotifyEvent::ePanNone;
3637 break;
3638 }
3639
3640 // Special check for trees
3641 if (nsTreeBodyFrame* treeFrame = do_QueryFrame(current)) {
3642 if (treeFrame->GetHorizontalOverflow()) {
3643 panDirection = WidgetGestureNotifyEvent::ePanHorizontal;
3644 }
3645 if (treeFrame->GetVerticalOverflow()) {
3646 panDirection = WidgetGestureNotifyEvent::ePanVertical;
3647 }
3648 break;
3649 }
3650
3651 if (ScrollContainerFrame* scrollContainerFrame = do_QueryFrame(current)) {
3652 layers::ScrollDirections scrollbarVisibility =
3653 scrollContainerFrame->GetScrollbarVisibility();
3654
3655 // Check if we have visible scrollbars
3656 if (scrollbarVisibility.contains(layers::ScrollDirection::eVertical)) {
3657 panDirection = WidgetGestureNotifyEvent::ePanVertical;
3658 displayPanFeedback = true;
3659 break;
3660 }
3661
3662 if (scrollbarVisibility.contains(layers::ScrollDirection::eHorizontal)) {
3663 panDirection = WidgetGestureNotifyEvent::ePanHorizontal;
3664 displayPanFeedback = true;
3665 }
3666 }
3667 } // ancestor chain
3668 aEvent->mDisplayPanFeedback = displayPanFeedback;
3669 aEvent->mPanDirection = panDirection;
3670}
3671
3672#ifdef XP_MACOSX
3673static nsINode* GetCrossDocParentNode(nsINode* aChild) {
3674 MOZ_ASSERT(aChild, "The child is null!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChild)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aChild))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aChild" " (" "The child is null!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3674); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild" ") ("
"The child is null!" ")"); do { *((volatile int*)__null) = 3674
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
3675 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3675); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 3675; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3676
3677 nsINode* parent = aChild->GetParentNode();
3678 if (parent && parent->IsContent() && aChild->IsContent()) {
3679 parent = aChild->AsContent()->GetFlattenedTreeParent();
3680 }
3681
3682 if (parent || !aChild->IsDocument()) {
3683 return parent;
3684 }
3685
3686 return aChild->AsDocument()->GetEmbedderElement();
3687}
3688
3689static bool NodeAllowsClickThrough(nsINode* aNode) {
3690 while (aNode) {
3691 if (aNode->IsAnyOfXULElements(nsGkAtoms::browser, nsGkAtoms::tree)) {
3692 return false;
3693 }
3694 if (aNode->IsAnyOfXULElements(nsGkAtoms::scrollbar, nsGkAtoms::resizer)) {
3695 return true;
3696 }
3697 aNode = GetCrossDocParentNode(aNode);
3698 }
3699 return true;
3700}
3701#endif
3702
3703void EventStateManager::PostHandleKeyboardEvent(
3704 WidgetKeyboardEvent* aKeyboardEvent, nsIFrame* aTargetFrame,
3705 nsEventStatus& aStatus) {
3706 if (aStatus == nsEventStatus_eConsumeNoDefault) {
3707 return;
3708 }
3709
3710 RefPtr<nsPresContext> presContext = mPresContext;
3711
3712 if (!aKeyboardEvent->HasBeenPostedToRemoteProcess()) {
3713 if (aKeyboardEvent->IsWaitingReplyFromRemoteProcess()) {
3714 RefPtr<BrowserParent> remote =
3715 aTargetFrame ? BrowserParent::GetFrom(aTargetFrame->GetContent())
3716 : nullptr;
3717 if (remote) {
3718 // remote is null-checked above in order to let pre-existing event
3719 // targeting code's chrome vs. content decision override in case of
3720 // disagreement in order not to disrupt non-Fission e10s mode in case
3721 // there are still bugs in the Fission-mode code. That is, if remote
3722 // is nullptr, the pre-existing event targeting code has deemed this
3723 // event to belong to chrome rather than content.
3724 BrowserParent* preciseRemote = BrowserParent::GetFocused();
3725 if (preciseRemote) {
3726 remote = preciseRemote;
3727 }
3728 // else there was a race between layout and focus tracking
3729 }
3730 if (remote && !remote->IsReadyToHandleInputEvents()) {
3731 // We need to dispatch the event to the browser element again if we were
3732 // waiting for the key reply but the event wasn't sent to the content
3733 // process due to the remote browser wasn't ready.
3734 WidgetKeyboardEvent keyEvent(*aKeyboardEvent);
3735 aKeyboardEvent->MarkAsHandledInRemoteProcess();
3736 RefPtr<Element> ownerElement = remote->GetOwnerElement();
3737 EventDispatcher::Dispatch(ownerElement, presContext, &keyEvent);
3738 if (keyEvent.DefaultPrevented()) {
3739 aKeyboardEvent->PreventDefault(!keyEvent.DefaultPreventedByContent());
3740 aStatus = nsEventStatus_eConsumeNoDefault;
3741 return;
3742 }
3743 }
3744 }
3745 // The widget expects a reply for every keyboard event. If the event wasn't
3746 // dispatched to a content process (non-e10s or no content process
3747 // running), we need to short-circuit here. Otherwise, we need to wait for
3748 // the content process to handle the event.
3749 if (aKeyboardEvent->mWidget) {
3750 aKeyboardEvent->mWidget->PostHandleKeyEvent(aKeyboardEvent);
3751 }
3752 if (aKeyboardEvent->DefaultPrevented()) {
3753 aStatus = nsEventStatus_eConsumeNoDefault;
3754 return;
3755 }
3756 }
3757
3758 // XXX Currently, our automated tests don't support mKeyNameIndex.
3759 // Therefore, we still need to handle this with keyCode.
3760 switch (aKeyboardEvent->mKeyCode) {
3761 case NS_VK_TAB:
3762 case NS_VK_F6:
3763 // This is to prevent keyboard scrolling while alt modifier in use.
3764 if (!aKeyboardEvent->IsAlt()) {
3765 aStatus = nsEventStatus_eConsumeNoDefault;
3766
3767 // Handling the tab event after it was sent to content is bad,
3768 // because to the FocusManager the remote-browser looks like one
3769 // element, so we would just move the focus to the next element
3770 // in chrome, instead of handling it in content.
3771 if (aKeyboardEvent->HasBeenPostedToRemoteProcess()) {
3772 break;
3773 }
3774
3775 EnsureDocument(presContext);
3776 nsFocusManager* fm = nsFocusManager::GetFocusManager();
3777 if (fm && mDocument) {
3778 // Shift focus forward or back depending on shift key
3779 bool isDocMove = aKeyboardEvent->IsControl() ||
3780 aKeyboardEvent->mKeyCode == NS_VK_F6;
3781 uint32_t dir =
3782 aKeyboardEvent->IsShift()
3783 ? (isDocMove ? static_cast<uint32_t>(
3784 nsIFocusManager::MOVEFOCUS_BACKWARDDOC)
3785 : static_cast<uint32_t>(
3786 nsIFocusManager::MOVEFOCUS_BACKWARD))
3787 : (isDocMove ? static_cast<uint32_t>(
3788 nsIFocusManager::MOVEFOCUS_FORWARDDOC)
3789 : static_cast<uint32_t>(
3790 nsIFocusManager::MOVEFOCUS_FORWARD));
3791 RefPtr<Element> result;
3792 fm->MoveFocus(mDocument->GetWindow(), nullptr, dir,
3793 nsIFocusManager::FLAG_BYKEY, getter_AddRefs(result));
3794 }
3795 }
3796 return;
3797 case 0:
3798 // We handle keys with no specific keycode value below.
3799 break;
3800 default:
3801 return;
3802 }
3803
3804 switch (aKeyboardEvent->mKeyNameIndex) {
3805 case KEY_NAME_INDEX_ZoomIn:
3806 case KEY_NAME_INDEX_ZoomOut:
3807 ChangeZoom(aKeyboardEvent->mKeyNameIndex == KEY_NAME_INDEX_ZoomIn);
3808 aStatus = nsEventStatus_eConsumeNoDefault;
3809 break;
3810 default:
3811 break;
3812 }
3813}
3814
3815static bool NeedsActiveContentChange(const WidgetMouseEvent* aMouseEvent) {
3816 // If the mouse event is a synthesized mouse event due to a touch, do
3817 // not set/clear the activation state. Element activation is handled by APZ.
3818 return !aMouseEvent ||
3819 aMouseEvent->mInputSource != MouseEvent_Binding::MOZ_SOURCE_TOUCH;
3820}
3821
3822nsresult EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
3823 WidgetEvent* aEvent,
3824 nsIFrame* aTargetFrame,
3825 nsEventStatus* aStatus,
3826 nsIContent* aOverrideClickTarget) {
3827 AUTO_PROFILER_LABEL("EventStateManager::PostHandleEvent", DOM)mozilla::AutoProfilerLabel raiiObject3827( "EventStateManager::PostHandleEvent"
, nullptr, JS::ProfilingCategoryPair::DOM)
;
3828 NS_ENSURE_ARG(aPresContext)do { if ((__builtin_expect(!!(!(aPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3828); return NS_ERROR_INVALID_ARG; } } while (false)
;
3829 NS_ENSURE_ARG_POINTER(aStatus)do { if ((__builtin_expect(!!(!(aStatus)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStatus" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3829); return NS_ERROR_INVALID_POINTER; } } while (false)
;
3830
3831 mCurrentTarget = aTargetFrame;
3832 mCurrentTargetContent = nullptr;
3833
3834 HandleCrossProcessEvent(aEvent, aStatus);
3835 // NOTE: the above call may have destroyed aTargetFrame, please use
3836 // mCurrentTarget henceforth. This is to avoid using it accidentally:
3837 aTargetFrame = nullptr;
3838
3839 // Most of the events we handle below require a frame.
3840 // Add special cases here.
3841 if (!mCurrentTarget && aEvent->mMessage != eMouseUp &&
3842 aEvent->mMessage != eMouseDown && aEvent->mMessage != eDragEnter &&
3843 aEvent->mMessage != eDragOver && aEvent->mMessage != ePointerUp &&
3844 aEvent->mMessage != ePointerCancel) {
3845 return NS_OK;
3846 }
3847
3848 // Keep the prescontext alive, we might need it after event dispatch
3849 RefPtr<nsPresContext> presContext = aPresContext;
3850 nsresult ret = NS_OK;
3851
3852 switch (aEvent->mMessage) {
3853 case eMouseDown: {
3854 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
3855 if (mouseEvent->mButton == MouseButton::ePrimary &&
3856 !sNormalLMouseEventInProcess) {
3857 // We got a mouseup event while a mousedown event was being processed.
3858 // Make sure that the capturing content is cleared.
3859 PresShell::ReleaseCapturingContent();
3860 break;
3861 }
3862
3863 // For remote content, capture the event in the parent process at the
3864 // <xul:browser remote> element. This will ensure that subsequent
3865 // mousemove/mouseup events will continue to be dispatched to this element
3866 // and therefore forwarded to the child.
3867 if (aEvent->HasBeenPostedToRemoteProcess() &&
3868 !PresShell::GetCapturingContent()) {
3869 if (nsIContent* content =
3870 mCurrentTarget ? mCurrentTarget->GetContent() : nullptr) {
3871 PresShell::SetCapturingContent(content, CaptureFlags::None, aEvent);
3872 } else {
3873 PresShell::ReleaseCapturingContent();
3874 }
3875 }
3876
3877 // If MouseEvent::PreventClickEvent() was called by chrome script,
3878 // we need to forget the clicking content and click count for the
3879 // following eMouseUp event.
3880 if (mouseEvent->mClickEventPrevented) {
3881 switch (mouseEvent->mButton) {
3882 case MouseButton::ePrimary:
3883 case MouseButton::eSecondary:
3884 case MouseButton::eMiddle: {
3885 LastMouseDownInfo& mouseDownInfo =
3886 GetLastMouseDownInfo(mouseEvent->mButton);
3887 mouseDownInfo.mLastMouseDownContent = nullptr;
3888 mouseDownInfo.mClickCount = 0;
3889 mouseDownInfo.mLastMouseDownInputControlType = Nothing();
3890 break;
3891 }
3892
3893 default:
3894 break;
3895 }
3896 }
3897
3898 nsCOMPtr<nsIContent> activeContent;
3899 // When content calls PreventDefault on pointerdown, we also call
3900 // PreventDefault on the subsequent mouse events to suppress default
3901 // behaviors. Normally, aStatus should be nsEventStatus_eConsumeNoDefault
3902 // when the event is DefaultPrevented but it's reset to
3903 // nsEventStatus_eIgnore in EventStateManager::PreHandleEvent. So we also
3904 // check if the event is DefaultPrevented.
3905 if (nsEventStatus_eConsumeNoDefault != *aStatus &&
3906 !aEvent->DefaultPrevented()) {
3907 nsCOMPtr<nsIContent> newFocus;
3908 bool suppressBlur = false;
3909 if (mCurrentTarget) {
3910 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(newFocus));
3911 activeContent = mCurrentTarget->GetContent();
3912
3913 // In some cases, we do not want to even blur the current focused
3914 // element. Those cases are:
3915 // 1. -moz-user-focus CSS property is set to 'ignore';
3916 // 2. XUL control element has the disabled property set to 'true'.
3917 //
3918 // We can't use nsIFrame::IsFocusable() because we want to blur when
3919 // we click on a visibility: none element.
3920 // We can't use nsIContent::IsFocusable() because we want to blur when
3921 // we click on a non-focusable element like a <div>.
3922 // We have to use |aEvent->mTarget| to not make sure we do not check
3923 // an anonymous node of the targeted element.
3924 suppressBlur =
3925 mCurrentTarget->StyleUI()->UserFocus() == StyleUserFocus::Ignore;
3926
3927 if (!suppressBlur) {
3928 if (Element* element =
3929 Element::FromEventTargetOrNull(aEvent->mTarget)) {
3930 if (nsCOMPtr<nsIDOMXULControlElement> xulControl =
3931 element->AsXULControl()) {
3932 bool disabled = false;
3933 xulControl->GetDisabled(&disabled);
3934 suppressBlur = disabled;
3935 }
3936 }
3937 }
3938 }
3939
3940 // When a root content which isn't editable but has an editable HTML
3941 // <body> element is clicked, we should redirect the focus to the
3942 // the <body> element. E.g., when an user click bottom of the editor
3943 // where is outside of the <body> element, the <body> should be focused
3944 // and the user can edit immediately after that.
3945 //
3946 // NOTE: The newFocus isn't editable that also means it's not in
3947 // designMode. In designMode, all contents are not focusable.
3948 if (newFocus && !newFocus->IsEditable()) {
3949 Document* doc = newFocus->GetComposedDoc();
3950 if (doc && newFocus == doc->GetRootElement()) {
3951 nsIContent* bodyContent =
3952 nsLayoutUtils::GetEditableRootContentByContentEditable(doc);
3953 if (bodyContent && bodyContent->GetPrimaryFrame()) {
3954 newFocus = bodyContent;
3955 }
3956 }
3957 }
3958
3959 // When the mouse is pressed, the default action is to focus the
3960 // target. Look for the nearest enclosing focusable frame.
3961 //
3962 // TODO: Probably this should be moved to Element::PostHandleEvent.
3963 for (; newFocus; newFocus = newFocus->GetFlattenedTreeParent()) {
3964 if (!newFocus->IsElement()) {
3965 continue;
3966 }
3967
3968 nsIFrame* frame = newFocus->GetPrimaryFrame();
3969 if (!frame) {
3970 continue;
3971 }
3972
3973 // If the mousedown happened inside a popup, don't try to set focus on
3974 // one of its containing elements
3975 if (frame->IsMenuPopupFrame()) {
3976 newFocus = nullptr;
3977 break;
3978 }
3979
3980 auto flags = IsFocusableFlags::WithMouse;
3981 if (frame->IsFocusable(flags)) {
3982 break;
3983 }
3984
3985 if (ShadowRoot* root = newFocus->GetShadowRoot()) {
3986 if (root->DelegatesFocus()) {
3987 if (Element* firstFocusable = root->GetFocusDelegate(flags)) {
3988 newFocus = firstFocusable;
3989 break;
3990 }
3991 }
3992 }
3993 }
3994
3995 MOZ_ASSERT_IF(newFocus, newFocus->IsElement())do { if (newFocus) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(newFocus->IsElement())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(newFocus->IsElement()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("newFocus->IsElement()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3995); AnnotateMozCrashReason("MOZ_ASSERT" "(" "newFocus->IsElement()"
")"); do { *((volatile int*)__null) = 3995; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
3996
3997 if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
3998 // if something was found to focus, focus it. Otherwise, if the
3999 // element that was clicked doesn't have -moz-user-focus: ignore,
4000 // clear the existing focus. For -moz-user-focus: ignore, the focus
4001 // is just left as is.
4002 // Another effect of mouse clicking, handled in Selection, is that
4003 // it should update the caret position to where the mouse was
4004 // clicked. Because the focus is cleared when clicking on a
4005 // non-focusable node, the next press of the tab key will cause
4006 // focus to be shifted from the caret position instead of the root.
4007 if (newFocus) {
4008 // use the mouse flag and the noscroll flag so that the content
4009 // doesn't unexpectedly scroll when clicking an element that is
4010 // only half visible
4011 uint32_t flags =
4012 nsIFocusManager::FLAG_BYMOUSE | nsIFocusManager::FLAG_NOSCROLL;
4013 // If this was a touch-generated event, pass that information:
4014 if (mouseEvent->mInputSource ==
4015 MouseEvent_Binding::MOZ_SOURCE_TOUCH) {
4016 flags |= nsIFocusManager::FLAG_BYTOUCH;
4017 }
4018 fm->SetFocus(MOZ_KnownLive(newFocus->AsElement())(newFocus->AsElement()), flags);
4019 } else if (!suppressBlur) {
4020 // clear the focus within the frame and then set it as the
4021 // focused frame
4022 EnsureDocument(mPresContext);
4023 if (mDocument) {
4024 nsCOMPtr<nsPIDOMWindowOuter> outerWindow = mDocument->GetWindow();
4025#ifdef XP_MACOSX
4026 if (!activeContent || !activeContent->IsXULElement())
4027#endif
4028 fm->ClearFocus(outerWindow);
4029 // Prevent switch frame if we're already not in the foreground tab
4030 // and we're in a content process.
4031 // TODO: If we were inactive frame in this tab, and now in
4032 // background tab, we shouldn't make the tab foreground, but
4033 // we should set focus to clicked document in the background
4034 // tab. However, nsFocusManager does not have proper method
4035 // for doing this. Therefore, we should skip setting focus
4036 // to clicked document for now.
4037 if (XRE_IsParentProcess() || IsInActiveTab(mDocument)) {
4038 fm->SetFocusedWindow(outerWindow);
4039 }
4040 }
4041 }
4042 }
4043
4044 // The rest is left button-specific.
4045 if (mouseEvent->mButton != MouseButton::ePrimary) {
4046 break;
4047 }
4048
4049 // The nearest enclosing element goes into the :active state. If we're
4050 // not an element (so we're text or something) we need to obtain
4051 // our parent element and put it into :active instead.
4052 if (activeContent && !activeContent->IsElement()) {
4053 if (nsIContent* par = activeContent->GetFlattenedTreeParent()) {
4054 activeContent = par;
4055 }
4056 }
4057 } else {
4058 // if we're here, the event handler returned false, so stop
4059 // any of our own processing of a drag. Workaround for bug 43258.
4060 StopTrackingDragGesture(true);
4061 }
4062 // XXX Why do we always set this is active? Active window may be changed
4063 // by a mousedown event listener.
4064 if (NeedsActiveContentChange(mouseEvent)) {
4065 SetActiveManager(this, activeContent);
4066 }
4067 } break;
4068 case ePointerCancel:
4069 case ePointerUp: {
4070 WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent();
4071 MOZ_ASSERT(pointerEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(pointerEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pointerEvent))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("pointerEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4071); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pointerEvent"
")"); do { *((volatile int*)__null) = 4071; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4072 // Implicitly releasing capture for given pointer. ePointerLostCapture
4073 // should be send after ePointerUp or ePointerCancel.
4074 PointerEventHandler::ImplicitlyReleasePointerCapture(pointerEvent);
4075 PointerEventHandler::UpdateActivePointerState(pointerEvent);
4076
4077 if (
4078 // After pointercancel, pointer becomes invalid so we can remove
4079 // relevant helper from table.
4080 pointerEvent->mMessage == ePointerCancel ||
4081 // pointerup for non-hoverable pointer needs to dispatch pointerout
4082 // and pointerleave events because the pointer is valid only while the
4083 // pointer is "down".
4084 !pointerEvent->InputSourceSupportsHover()) {
4085 GenerateMouseEnterExit(pointerEvent);
4086 mPointersEnterLeaveHelper.Remove(pointerEvent->pointerId);
4087 }
4088
4089 break;
4090 }
4091 case eMouseUp: {
4092 // We can unconditionally stop capturing because
4093 // we should never be capturing when the mouse button is up
4094 PresShell::ReleaseCapturingContent();
4095
4096 WidgetMouseEvent* mouseUpEvent = aEvent->AsMouseEvent();
4097 if (NeedsActiveContentChange(mouseUpEvent)) {
4098 ClearGlobalActiveContent(this);
4099 }
4100 if (mouseUpEvent && EventCausesClickEvents(*mouseUpEvent)) {
4101 // Make sure to dispatch the click even if there is no frame for
4102 // the current target element. This is required for Web compatibility.
4103 RefPtr<EventStateManager> esm =
4104 ESMFromContentOrThis(aOverrideClickTarget);
4105 ret =
4106 esm->PostHandleMouseUp(mouseUpEvent, aStatus, aOverrideClickTarget);
4107 }
4108
4109 if (PresShell* presShell = presContext->GetPresShell()) {
4110 RefPtr<nsFrameSelection> frameSelection = presShell->FrameSelection();
4111 frameSelection->SetDragState(false);
4112 }
4113 } break;
4114 case eWheelOperationEnd: {
4115 MOZ_ASSERT(aEvent->IsTrusted())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->IsTrusted())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->IsTrusted()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->IsTrusted()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4115); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsTrusted()"
")"); do { *((volatile int*)__null) = 4115; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4116 ScrollbarsForWheel::MayInactivate();
4117 WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
4118 ScrollContainerFrame* scrollTarget =
4119 ComputeScrollTargetAndMayAdjustWheelEvent(
4120 mCurrentTarget, wheelEvent,
4121 COMPUTE_DEFAULT_ACTION_TARGET_WITH_AUTO_DIR);
4122 // If the wheel event was handled by APZ, APZ will perform the scroll
4123 // snap.
4124 if (scrollTarget && !WheelTransaction::HandledByApz()) {
4125 scrollTarget->ScrollSnap();
4126 }
4127 } break;
4128 case eWheel:
4129 case eWheelOperationStart: {
4130 MOZ_ASSERT(aEvent->IsTrusted())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->IsTrusted())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->IsTrusted()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->IsTrusted()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4130); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsTrusted()"
")"); do { *((volatile int*)__null) = 4130; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4131
4132 if (*aStatus == nsEventStatus_eConsumeNoDefault) {
4133 ScrollbarsForWheel::Inactivate();
4134 break;
4135 }
4136
4137 WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
4138 MOZ_ASSERT(wheelEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(wheelEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(wheelEvent))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("wheelEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4138); AnnotateMozCrashReason("MOZ_ASSERT" "(" "wheelEvent"
")"); do { *((volatile int*)__null) = 4138; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4139
4140 // When APZ is enabled, the actual scroll animation might be handled by
4141 // the compositor.
4142 WheelPrefs::Action action =
4143 wheelEvent->mFlags.mHandledByAPZ
4144 ? WheelPrefs::ACTION_NONE
4145 : WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent);
4146
4147 WheelDeltaAdjustmentStrategy strategy =
4148 GetWheelDeltaAdjustmentStrategy(*wheelEvent);
4149 // Adjust the delta values of the wheel event if the current default
4150 // action is to horizontalize scrolling. I.e., deltaY values are set to
4151 // deltaX and deltaY and deltaZ values are set to 0.
4152 // If horizontalized, the delta values will be restored and its overflow
4153 // deltaX will become 0 when the WheelDeltaHorizontalizer instance is
4154 // being destroyed.
4155 WheelDeltaHorizontalizer horizontalizer(*wheelEvent);
4156 if (WheelDeltaAdjustmentStrategy::eHorizontalize == strategy) {
4157 horizontalizer.Horizontalize();
4158 }
4159
4160 // Since ComputeScrollTargetAndMayAdjustWheelEvent() may adjust the delta
4161 // if the event is auto-dir. So we use |ESMAutoDirWheelDeltaRestorer|
4162 // here.
4163 // An instance of |ESMAutoDirWheelDeltaRestorer| is used to monitor
4164 // auto-dir adjustment which may happen during its lifetime. If the delta
4165 // values is adjusted during its lifetime, the instance will restore the
4166 // adjusted delta when it's being destrcuted.
4167 ESMAutoDirWheelDeltaRestorer restorer(*wheelEvent);
4168 ScrollContainerFrame* scrollTarget =
4169 ComputeScrollTargetAndMayAdjustWheelEvent(
4170 mCurrentTarget, wheelEvent,
4171 COMPUTE_DEFAULT_ACTION_TARGET_WITH_AUTO_DIR);
4172
4173 switch (action) {
4174 case WheelPrefs::ACTION_SCROLL:
4175 case WheelPrefs::ACTION_HORIZONTALIZED_SCROLL: {
4176 // For scrolling of default action, we should honor the mouse wheel
4177 // transaction.
4178
4179 ScrollbarsForWheel::PrepareToScrollText(this, mCurrentTarget,
4180 wheelEvent);
4181
4182 if (aEvent->mMessage != eWheel ||
4183 (!wheelEvent->mDeltaX && !wheelEvent->mDeltaY)) {
4184 break;
4185 }
4186
4187 ScrollbarsForWheel::SetActiveScrollTarget(scrollTarget);
4188
4189 ScrollContainerFrame* rootScrollContainerFrame =
4190 !mCurrentTarget
4191 ? nullptr
4192 : mCurrentTarget->PresShell()->GetRootScrollContainerFrame();
4193 if (!scrollTarget || scrollTarget == rootScrollContainerFrame) {
4194 wheelEvent->mViewPortIsOverscrolled = true;
4195 }
4196 wheelEvent->mOverflowDeltaX = wheelEvent->mDeltaX;
4197 wheelEvent->mOverflowDeltaY = wheelEvent->mDeltaY;
4198 WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(
4199 wheelEvent);
4200 if (scrollTarget) {
4201 DoScrollText(scrollTarget, wheelEvent);
4202 } else {
4203 WheelTransaction::EndTransaction();
4204 ScrollbarsForWheel::Inactivate();
4205 }
4206 break;
4207 }
4208 case WheelPrefs::ACTION_HISTORY: {
4209 // If this event doesn't cause eLegacyMouseLineOrPageScroll event or
4210 // the direction is oblique, don't perform history back/forward.
4211 int32_t intDelta = wheelEvent->GetPreferredIntDelta();
4212 if (!intDelta) {
4213 break;
4214 }
4215 DoScrollHistory(intDelta);
4216 break;
4217 }
4218 case WheelPrefs::ACTION_ZOOM: {
4219 // If this event doesn't cause eLegacyMouseLineOrPageScroll event or
4220 // the direction is oblique, don't perform zoom in/out.
4221 int32_t intDelta = wheelEvent->GetPreferredIntDelta();
4222 if (!intDelta) {
4223 break;
4224 }
4225 DoScrollZoom(mCurrentTarget, intDelta);
4226 break;
4227 }
4228 case WheelPrefs::ACTION_NONE:
4229 default:
4230 bool allDeltaOverflown = false;
4231 if (StaticPrefs::dom_event_wheel_event_groups_enabled() &&
4232 (wheelEvent->mDeltaX != 0.0 || wheelEvent->mDeltaY != 0.0)) {
4233 if (scrollTarget) {
4234 WheelTransaction::WillHandleDefaultAction(
4235 wheelEvent, scrollTarget, mCurrentTarget);
4236 } else {
4237 WheelTransaction::EndTransaction();
4238 }
4239 }
4240 if (wheelEvent->mFlags.mHandledByAPZ) {
4241 if (wheelEvent->mCanTriggerSwipe) {
4242 // For events that can trigger swipes, APZ needs to know whether
4243 // scrolling is possible in the requested direction. It does this
4244 // by looking at the scroll overflow values on mCanTriggerSwipe
4245 // events after they have been processed.
4246 allDeltaOverflown = !ComputeScrollTarget(
4247 mCurrentTarget, wheelEvent, COMPUTE_DEFAULT_ACTION_TARGET);
4248 }
4249 } else {
4250 // The event was processed neither by APZ nor by us, so all of the
4251 // delta values must be overflown delta values.
4252 allDeltaOverflown = true;
4253 }
4254
4255 if (!allDeltaOverflown) {
4256 break;
4257 }
4258 wheelEvent->mOverflowDeltaX = wheelEvent->mDeltaX;
4259 wheelEvent->mOverflowDeltaY = wheelEvent->mDeltaY;
4260 WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(
4261 wheelEvent);
4262 wheelEvent->mViewPortIsOverscrolled = true;
4263 break;
4264 }
4265 *aStatus = nsEventStatus_eConsumeNoDefault;
4266 } break;
4267
4268 case eGestureNotify: {
4269 if (nsEventStatus_eConsumeNoDefault != *aStatus) {
4270 DecideGestureEvent(aEvent->AsGestureNotifyEvent(), mCurrentTarget);
4271 }
4272 } break;
4273
4274 case eDragEnter:
4275 case eDragOver: {
4276 NS_ASSERTION(aEvent->mClass == eDragEventClass, "Expected a drag event")do { if (!(aEvent->mClass == eDragEventClass)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Expected a drag event", "aEvent->mClass == eDragEventClass"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4276); MOZ_PretendNoReturn(); } } while (0)
;
4277
4278 // Check if the drag is occurring inside a scrollable area. If so, scroll
4279 // the area when the mouse is near the edges.
4280 if (mCurrentTarget && aEvent->mMessage == eDragOver) {
4281 nsIFrame* checkFrame = mCurrentTarget;
4282 while (checkFrame) {
4283 ScrollContainerFrame* scrollFrame = do_QueryFrame(checkFrame);
4284 // Break out so only the innermost scrollframe is scrolled.
4285 if (scrollFrame && scrollFrame->DragScroll(aEvent)) {
4286 break;
4287 }
4288 checkFrame = checkFrame->GetParent();
4289 }
4290 }
4291
4292 nsCOMPtr<nsIDragSession> dragSession =
4293 nsContentUtils::GetDragSession(mPresContext);
4294 if (!dragSession) break;
4295
4296 // Reset the flag.
4297 dragSession->SetOnlyChromeDrop(false);
4298 if (mPresContext) {
4299 EnsureDocument(mPresContext);
4300 }
4301 bool isChromeDoc = nsContentUtils::IsChromeDoc(mDocument);
4302
4303 // the initial dataTransfer is the one from the dragstart event that
4304 // was set on the dragSession when the drag began.
4305 RefPtr<DataTransfer> dataTransfer;
4306 RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer();
4307
4308 WidgetDragEvent* dragEvent = aEvent->AsDragEvent();
4309
4310 // collect any changes to moz cursor settings stored in the event's
4311 // data transfer.
4312 UpdateDragDataTransfer(dragEvent);
4313
4314 // cancelling a dragenter or dragover event means that a drop should be
4315 // allowed, so update the dropEffect and the canDrop state to indicate
4316 // that a drag is allowed. If the event isn't cancelled, a drop won't be
4317 // allowed. Essentially, to allow a drop somewhere, specify the effects
4318 // using the effectAllowed and dropEffect properties in a dragenter or
4319 // dragover event and cancel the event. To not allow a drop somewhere,
4320 // don't cancel the event or set the effectAllowed or dropEffect to
4321 // "none". This way, if the event is just ignored, no drop will be
4322 // allowed.
4323 uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
4324 uint32_t action = nsIDragService::DRAGDROP_ACTION_NONE;
4325 if (nsEventStatus_eConsumeNoDefault == *aStatus) {
4326 // If the event has initialized its mDataTransfer, use it.
4327 // Or the event has not been initialized its mDataTransfer, but
4328 // it's set before dispatch because of synthesized, but without
4329 // testing session (e.g., emulating drag from another app), use it
4330 // coming from outside.
4331 // XXX Perhaps, for the latter case, we need new API because we don't
4332 // have a chance to initialize allowed effects of the session.
4333 if (dragEvent->mDataTransfer) {
4334 // get the dataTransfer and the dropEffect that was set on it
4335 dataTransfer = dragEvent->mDataTransfer;
4336 dropEffect = dataTransfer->DropEffectInt();
4337 } else {
4338 // if dragEvent->mDataTransfer is null, it means that no attempt was
4339 // made to access the dataTransfer during the event, yet the event
4340 // was cancelled. Instead, use the initial data transfer available
4341 // from the drag session. The drop effect would not have been
4342 // initialized (which is done in DragEvent::GetDataTransfer),
4343 // so set it from the drag action. We'll still want to filter it
4344 // based on the effectAllowed below.
4345 dataTransfer = initialDataTransfer;
4346
4347 dragSession->GetDragAction(&action);
4348
4349 // filter the drop effect based on the action. Use UNINITIALIZED as
4350 // any effect is allowed.
4351 dropEffect = nsContentUtils::FilterDropEffect(
4352 action, nsIDragService::DRAGDROP_ACTION_UNINITIALIZED);
4353 }
4354
4355 // At this point, if the dataTransfer is null, it means that the
4356 // drag was originally started by directly calling the drag service.
4357 // Just assume that all effects are allowed.
4358 uint32_t effectAllowed = nsIDragService::DRAGDROP_ACTION_UNINITIALIZED;
4359 if (dataTransfer) {
4360 effectAllowed = dataTransfer->EffectAllowedInt();
4361 }
4362
4363 // set the drag action based on the drop effect and effect allowed.
4364 // The drop effect field on the drag transfer object specifies the
4365 // desired current drop effect. However, it cannot be used if the
4366 // effectAllowed state doesn't include that type of action. If the
4367 // dropEffect is "none", then the action will be 'none' so a drop will
4368 // not be allowed.
4369 if (effectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED ||
4370 dropEffect & effectAllowed)
4371 action = dropEffect;
4372
4373 if (action == nsIDragService::DRAGDROP_ACTION_NONE)
4374 dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
4375
4376 // inform the drag session that a drop is allowed on this node.
4377 dragSession->SetDragAction(action);
4378 dragSession->SetCanDrop(action != nsIDragService::DRAGDROP_ACTION_NONE);
4379
4380 // For now, do this only for dragover.
4381 // XXXsmaug dragenter needs some more work.
4382 if (aEvent->mMessage == eDragOver && !isChromeDoc) {
4383 // Someone has called preventDefault(), check whether is was on
4384 // content or chrome.
4385 dragSession->SetOnlyChromeDrop(
4386 !dragEvent->mDefaultPreventedOnContent);
4387 }
4388 } else if (aEvent->mMessage == eDragOver && !isChromeDoc) {
4389 // No one called preventDefault(), so handle drop only in chrome.
4390 dragSession->SetOnlyChromeDrop(true);
4391 }
4392 if (auto* bc = BrowserChild::GetFrom(presContext->GetDocShell())) {
4393 bc->SendUpdateDropEffect(action, dropEffect);
4394 }
4395 if (aEvent->HasBeenPostedToRemoteProcess()) {
4396 dragSession->SetCanDrop(true);
4397 } else if (initialDataTransfer) {
4398 // Now set the drop effect in the initial dataTransfer. This ensures
4399 // that we can get the desired drop effect in the drop event. For events
4400 // dispatched to content, the content process will take care of setting
4401 // this.
4402 initialDataTransfer->SetDropEffectInt(dropEffect);
4403 }
4404 } break;
4405
4406 case eDrop: {
4407 if (aEvent->mFlags.mIsSynthesizedForTests) {
4408 nsCOMPtr<nsIDragService> dragService =
4409 do_GetService("@mozilla.org/widget/dragservice;1");
4410 nsCOMPtr<nsIDragSession> dragSession =
4411 nsContentUtils::GetDragSession(mPresContext);
4412 if (dragSession && dragService &&
4413 !dragService->GetNeverAllowSessionIsSynthesizedForTests()) {
4414 MOZ_ASSERT(dragSession->IsSynthesizedForTests())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(dragSession->IsSynthesizedForTests())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(dragSession->IsSynthesizedForTests()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("dragSession->IsSynthesizedForTests()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4414); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dragSession->IsSynthesizedForTests()"
")"); do { *((volatile int*)__null) = 4414; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4415 RefPtr<WindowContext> sourceWC;
4416 DebugOnly<nsresult> rvIgnored =
4417 dragSession->GetSourceWindowContext(getter_AddRefs(sourceWC));
4418 NS_WARNING_ASSERTION(do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "nsIDragSession::GetSourceDocument() failed, but ignored"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4420); } } while (false)
4419 NS_SUCCEEDED(rvIgnored),do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "nsIDragSession::GetSourceDocument() failed, but ignored"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4420); } } while (false)
4420 "nsIDragSession::GetSourceDocument() failed, but ignored")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "nsIDragSession::GetSourceDocument() failed, but ignored"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4420); } } while (false)
;
4421 // If the drag source hasn't been initialized, i.e., dragstart was
4422 // consumed by the test, the test needs to dispatch "dragend" event
4423 // instead of the drag session. Therefore, it does not make sense
4424 // to set drag end point in such case (you hit assersion if you do
4425 // it).
4426 if (sourceWC) {
4427 CSSIntPoint dropPointInScreen =
4428 Event::GetScreenCoords(aPresContext, aEvent, aEvent->mRefPoint)
4429 .extract();
4430 dragSession->SetDragEndPointForTests(dropPointInScreen.x,
4431 dropPointInScreen.y);
4432 }
4433 }
4434 }
4435 sLastDragOverFrame = nullptr;
4436 ClearGlobalActiveContent(this);
4437 break;
4438 }
4439 case eDragExit: {
4440 // make sure to fire the enter and exit_synth events after the
4441 // eDragExit event, otherwise we'll clean up too early
4442 GenerateDragDropEnterExit(presContext, aEvent->AsDragEvent());
4443 if (auto* bc = BrowserChild::GetFrom(presContext->GetDocShell())) {
4444 // SendUpdateDropEffect to prevent nsIDragService from waiting for
4445 // response of forwarded dragexit event.
4446 bc->SendUpdateDropEffect(nsIDragService::DRAGDROP_ACTION_NONE,
4447 nsIDragService::DRAGDROP_ACTION_NONE);
4448 }
4449 break;
4450 }
4451 case eKeyUp:
4452 // If space key is released, we need to inactivate the element which was
4453 // activated by preceding space key down.
4454 // XXX Currently, we don't store the reason of activation. Therefore,
4455 // this may cancel what is activated by a mousedown, but it must not
4456 // cause actual problem in web apps in the wild since it must be
4457 // rare case that users release space key during a mouse click/drag.
4458 if (aEvent->AsKeyboardEvent()->ShouldWorkAsSpaceKey()) {
4459 ClearGlobalActiveContent(this);
4460 }
4461 break;
4462
4463 case eKeyPress: {
4464 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
4465 PostHandleKeyboardEvent(keyEvent, mCurrentTarget, *aStatus);
4466 } break;
4467
4468 case eMouseEnterIntoWidget:
4469 if (mCurrentTarget) {
4470 nsCOMPtr<nsIContent> targetContent;
4471 mCurrentTarget->GetContentForEvent(aEvent,
4472 getter_AddRefs(targetContent));
4473 SetContentState(targetContent, ElementState::HOVER);
4474 }
4475 break;
4476
4477 case eMouseExitFromWidget:
4478 PointerEventHandler::UpdateActivePointerState(aEvent->AsMouseEvent());
4479 break;
4480
4481#ifdef XP_MACOSX
4482 case eMouseActivate:
4483 if (mCurrentTarget) {
4484 nsCOMPtr<nsIContent> targetContent;
4485 mCurrentTarget->GetContentForEvent(aEvent,
4486 getter_AddRefs(targetContent));
4487 if (!NodeAllowsClickThrough(targetContent)) {
4488 *aStatus = nsEventStatus_eConsumeNoDefault;
4489 }
4490 }
4491 break;
4492#endif
4493
4494 default:
4495 break;
4496 }
4497
4498 // Reset target frame to null to avoid mistargeting after reentrant event
4499 mCurrentTarget = nullptr;
4500 mCurrentTargetContent = nullptr;
4501
4502 return ret;
4503}
4504
4505BrowserParent* EventStateManager::GetCrossProcessTarget() {
4506 return IMEStateManager::GetActiveBrowserParent();
4507}
4508
4509bool EventStateManager::IsTargetCrossProcess(WidgetGUIEvent* aEvent) {
4510 // Check to see if there is a focused, editable content in chrome,
4511 // in that case, do not forward IME events to content
4512 Element* focusedElement = GetFocusedElement();
4513 if (focusedElement && focusedElement->IsEditable()) {
4514 return false;
4515 }
4516 return IMEStateManager::GetActiveBrowserParent() != nullptr;
4517}
4518
4519void EventStateManager::NotifyDestroyPresContext(nsPresContext* aPresContext) {
4520 RefPtr<nsPresContext> presContext = aPresContext;
4521 if (presContext) {
4522 IMEStateManager::OnDestroyPresContext(*presContext);
4523 }
4524
4525 // Bug 70855: Presentation is going away, possibly for a reframe.
4526 // Reset the hover state so that if we're recreating the presentation,
4527 // we won't have the old hover state still set in the new presentation,
4528 // as if the new presentation is resized, a new element may be hovered.
4529 ResetHoverState();
4530
4531 mMouseEnterLeaveHelper = nullptr;
4532 mPointersEnterLeaveHelper.Clear();
4533 PointerEventHandler::NotifyDestroyPresContext(presContext);
4534}
4535
4536void EventStateManager::ResetHoverState() {
4537 if (mHoverContent) {
4538 SetContentState(nullptr, ElementState::HOVER);
4539 }
4540}
4541
4542void EventStateManager::SetPresContext(nsPresContext* aPresContext) {
4543 mPresContext = aPresContext;
4544}
4545
4546void EventStateManager::ClearFrameRefs(nsIFrame* aFrame) {
4547 if (aFrame && aFrame == mCurrentTarget) {
4548 mCurrentTargetContent = aFrame->GetContent();
4549 }
4550}
4551
4552struct CursorImage {
4553 gfx::IntPoint mHotspot;
4554 nsCOMPtr<imgIContainer> mContainer;
4555 ImageResolution mResolution;
4556 bool mEarlierCursorLoading = false;
4557};
4558
4559// Given the event that we're processing, and the computed cursor and hotspot,
4560// determine whether the custom CSS cursor should be blocked (that is, not
4561// honored).
4562//
4563// We will not honor it all of the following are true:
4564//
4565// * the size of the custom cursor is bigger than layout.cursor.block.max-size.
4566// * the bounds of the cursor would end up outside of the viewport of the
4567// top-level content document.
4568//
4569// This is done in order to prevent hijacking the cursor, see bug 1445844 and
4570// co.
4571static bool ShouldBlockCustomCursor(nsPresContext* aPresContext,
4572 WidgetEvent* aEvent,
4573 const CursorImage& aCursor) {
4574 int32_t width = 0;
4575 int32_t height = 0;
4576 aCursor.mContainer->GetWidth(&width);
4577 aCursor.mContainer->GetHeight(&height);
4578 aCursor.mResolution.ApplyTo(width, height);
4579
4580 int32_t maxSize = StaticPrefs::layout_cursor_block_max_size();
4581
4582 if (width <= maxSize && height <= maxSize) {
4583 return false;
4584 }
4585
4586 auto input = DOMIntersectionObserver::ComputeInput(*aPresContext->Document(),
4587 nullptr, nullptr);
4588
4589 if (!input.mRootFrame) {
4590 return false;
4591 }
4592
4593 nsPoint point = nsLayoutUtils::GetEventCoordinatesRelativeTo(
4594 aEvent, RelativeTo{input.mRootFrame});
4595
4596 // The cursor size won't be affected by our full zoom in the parent process,
4597 // so undo that before checking the rect.
4598 float zoom = aPresContext->GetFullZoom();
4599
4600 // Also adjust for accessibility cursor scaling factor.
4601 zoom /= LookAndFeel::GetFloat(LookAndFeel::FloatID::CursorScale, 1.0f);
4602
4603 nsSize size(CSSPixel::ToAppUnits(width / zoom),
4604 CSSPixel::ToAppUnits(height / zoom));
4605 nsPoint hotspot(
4606 CSSPixel::ToAppUnits(ViewAs<CSSPixel>(aCursor.mHotspot.x / zoom)),
4607 CSSPixel::ToAppUnits(ViewAs<CSSPixel>(aCursor.mHotspot.y / zoom)));
4608
4609 const nsRect cursorRect(point - hotspot, size);
4610 auto output = DOMIntersectionObserver::Intersect(input, cursorRect);
4611 return !output.mIntersectionRect ||
4612 !(*output.mIntersectionRect == cursorRect);
4613}
4614
4615static gfx::IntPoint ComputeHotspot(imgIContainer* aContainer,
4616 const Maybe<gfx::Point>& aHotspot) {
4617 MOZ_ASSERT(aContainer)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContainer)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aContainer))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aContainer", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4617); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContainer"
")"); do { *((volatile int*)__null) = 4617; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4618
4619 // css3-ui says to use the CSS-specified hotspot if present,
4620 // otherwise use the intrinsic hotspot, otherwise use the top left
4621 // corner.
4622 if (aHotspot) {
4623 int32_t imgWidth, imgHeight;
4624 aContainer->GetWidth(&imgWidth);
4625 aContainer->GetHeight(&imgHeight);
4626 auto hotspot = gfx::IntPoint::Round(*aHotspot);
4627 return {std::max(std::min(hotspot.x.value, imgWidth - 1), 0),
4628 std::max(std::min(hotspot.y.value, imgHeight - 1), 0)};
4629 }
4630
4631 gfx::IntPoint hotspot;
4632 aContainer->GetHotspotX(&hotspot.x.value);
4633 aContainer->GetHotspotY(&hotspot.y.value);
4634 return hotspot;
4635}
4636
4637static CursorImage ComputeCustomCursor(nsPresContext* aPresContext,
4638 WidgetEvent* aEvent,
4639 const nsIFrame& aFrame,
4640 const nsIFrame::Cursor& aCursor) {
4641 if (aCursor.mAllowCustomCursor == nsIFrame::AllowCustomCursorImage::No) {
4642 return {};
4643 }
4644 const ComputedStyle& style =
4645 aCursor.mStyle ? *aCursor.mStyle : *aFrame.Style();
4646
4647 // If we are falling back because any cursor before us is loading, let the
4648 // consumer know.
4649 bool loading = false;
4650 for (const auto& image : style.StyleUI()->Cursor().images.AsSpan()) {
4651 MOZ_ASSERT(image.image.IsImageRequestType(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(image.image.IsImageRequestType())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(image.image.IsImageRequestType
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("image.image.IsImageRequestType()" " (" "Cursor image should only parse url() types"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4652); AnnotateMozCrashReason("MOZ_ASSERT" "(" "image.image.IsImageRequestType()"
") (" "Cursor image should only parse url() types" ")"); do {
*((volatile int*)__null) = 4652; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
4652 "Cursor image should only parse url() types")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(image.image.IsImageRequestType())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(image.image.IsImageRequestType
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("image.image.IsImageRequestType()" " (" "Cursor image should only parse url() types"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4652); AnnotateMozCrashReason("MOZ_ASSERT" "(" "image.image.IsImageRequestType()"
") (" "Cursor image should only parse url() types" ")"); do {
*((volatile int*)__null) = 4652; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
4653 uint32_t status;
4654 imgRequestProxy* req = image.image.GetImageRequest();
4655 if (!req || NS_FAILED(req->GetImageStatus(&status))((bool)(__builtin_expect(!!(NS_FAILED_impl(req->GetImageStatus
(&status))), 0)))
) {
4656 continue;
4657 }
4658 if (!(status & imgIRequest::STATUS_LOAD_COMPLETE)) {
4659 loading = true;
4660 continue;
4661 }
4662 if (status & imgIRequest::STATUS_ERROR) {
4663 continue;
4664 }
4665 nsCOMPtr<imgIContainer> container;
4666 req->GetImage(getter_AddRefs(container));
4667 if (!container) {
4668 continue;
4669 }
4670 StyleImageOrientation orientation =
4671 aFrame.StyleVisibility()->UsedImageOrientation(req);
4672 container = nsLayoutUtils::OrientImage(container, orientation);
4673 Maybe<gfx::Point> specifiedHotspot =
4674 image.has_hotspot ? Some(gfx::Point{image.hotspot_x, image.hotspot_y})
4675 : Nothing();
4676 gfx::IntPoint hotspot = ComputeHotspot(container, specifiedHotspot);
4677 CursorImage result{hotspot, std::move(container),
4678 image.image.GetResolution(style), loading};
4679 if (ShouldBlockCustomCursor(aPresContext, aEvent, result)) {
4680 continue;
4681 }
4682 // This is the one we want!
4683 return result;
4684 }
4685 return {{}, nullptr, {}, loading};
4686}
4687
4688void EventStateManager::UpdateCursor(nsPresContext* aPresContext,
4689 WidgetMouseEvent* aEvent,
4690 nsIFrame* aTargetFrame,
4691 nsEventStatus* aStatus) {
4692 if (aTargetFrame && IsRemoteTarget(aTargetFrame->GetContent())) {
4693 return;
4694 }
4695
4696 auto cursor = StyleCursorKind::Default;
4697 nsCOMPtr<imgIContainer> container;
4698 ImageResolution resolution;
4699 Maybe<gfx::IntPoint> hotspot;
4700
4701 if (mHidingCursorWhileTyping && aEvent->IsReal()) {
4702 // Any non-synthetic mouse event makes us show the cursor again.
4703 mHidingCursorWhileTyping = false;
4704 }
4705
4706 if (mHidingCursorWhileTyping) {
4707 cursor = StyleCursorKind::None;
4708 } else if (mLockCursor != kInvalidCursorKind) {
4709 // If cursor is locked just use the locked one
4710 cursor = mLockCursor;
4711 } else if (aTargetFrame) {
4712 // If not locked, look for correct cursor
4713 nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(
4714 aEvent, RelativeTo{aTargetFrame});
4715 const nsIFrame::Cursor framecursor = aTargetFrame->GetCursor(pt);
4716 const CursorImage customCursor =
4717 ComputeCustomCursor(aPresContext, aEvent, *aTargetFrame, framecursor);
4718
4719 // If the current cursor is from the same frame, and it is now
4720 // loading some new image for the cursor, we should wait for a
4721 // while rather than taking its fallback cursor directly.
4722 if (customCursor.mEarlierCursorLoading &&
4723 gLastCursorSourceFrame == aTargetFrame &&
4724 TimeStamp::NowLoRes() - gLastCursorUpdateTime <
4725 TimeDuration::FromMilliseconds(kCursorLoadingTimeout)) {
4726 return;
4727 }
4728 cursor = framecursor.mCursor;
4729 container = std::move(customCursor.mContainer);
4730 resolution = customCursor.mResolution;
4731 hotspot = Some(customCursor.mHotspot);
4732 }
4733
4734 if (aTargetFrame) {
4735 if (cursor == StyleCursorKind::Pointer && IsSelectingLink(aTargetFrame)) {
4736 cursor = aTargetFrame->GetWritingMode().IsVertical()
4737 ? StyleCursorKind::VerticalText
4738 : StyleCursorKind::Text;
4739 }
4740 SetCursor(cursor, container, resolution, hotspot,
4741 aTargetFrame->GetNearestWidget(), false);
4742 gLastCursorSourceFrame = aTargetFrame;
4743 gLastCursorUpdateTime = TimeStamp::NowLoRes();
4744 }
4745
4746 if (mLockCursor != kInvalidCursorKind || StyleCursorKind::Auto != cursor) {
4747 *aStatus = nsEventStatus_eConsumeDoDefault;
4748 }
4749}
4750
4751void EventStateManager::ClearCachedWidgetCursor(nsIFrame* aTargetFrame) {
4752 if (!aTargetFrame) {
4753 return;
4754 }
4755 nsIWidget* aWidget = aTargetFrame->GetNearestWidget();
4756 if (!aWidget) {
4757 return;
4758 }
4759 aWidget->ClearCachedCursor();
4760}
4761
4762void EventStateManager::StartHidingCursorWhileTyping(nsIWidget* aWidget) {
4763 if (mHidingCursorWhileTyping || sCursorSettingManager != this) {
4764 return;
4765 }
4766 mHidingCursorWhileTyping = true;
4767 SetCursor(StyleCursorKind::None, nullptr, {}, {}, aWidget, false);
4768}
4769
4770nsresult EventStateManager::SetCursor(StyleCursorKind aCursor,
4771 imgIContainer* aContainer,
4772 const ImageResolution& aResolution,
4773 const Maybe<gfx::IntPoint>& aHotspot,
4774 nsIWidget* aWidget, bool aLockCursor) {
4775 EnsureDocument(mPresContext);
4776 NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(mDocument)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mDocument" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4776); return NS_ERROR_FAILURE; } } while (false)
;
4777 sCursorSettingManager = this;
4778
4779 NS_ENSURE_TRUE(aWidget, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(aWidget)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aWidget" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4779); return NS_ERROR_FAILURE; } } while (false)
;
4780 if (aLockCursor) {
4781 if (StyleCursorKind::Auto != aCursor) {
4782 mLockCursor = aCursor;
4783 } else {
4784 // If cursor style is set to auto we unlock the cursor again.
4785 mLockCursor = kInvalidCursorKind;
4786 }
4787 }
4788 nsCursor c;
4789 switch (aCursor) {
4790 case StyleCursorKind::Auto:
4791 case StyleCursorKind::Default:
4792 c = eCursor_standard;
4793 break;
4794 case StyleCursorKind::Pointer:
4795 c = eCursor_hyperlink;
4796 break;
4797 case StyleCursorKind::Crosshair:
4798 c = eCursor_crosshair;
4799 break;
4800 case StyleCursorKind::Move:
4801 c = eCursor_move;
4802 break;
4803 case StyleCursorKind::Text:
4804 c = eCursor_select;
4805 break;
4806 case StyleCursorKind::Wait:
4807 c = eCursor_wait;
4808 break;
4809 case StyleCursorKind::Help:
4810 c = eCursor_help;
4811 break;
4812 case StyleCursorKind::NResize:
4813 c = eCursor_n_resize;
4814 break;
4815 case StyleCursorKind::SResize:
4816 c = eCursor_s_resize;
4817 break;
4818 case StyleCursorKind::WResize:
4819 c = eCursor_w_resize;
4820 break;
4821 case StyleCursorKind::EResize:
4822 c = eCursor_e_resize;
4823 break;
4824 case StyleCursorKind::NwResize:
4825 c = eCursor_nw_resize;
4826 break;
4827 case StyleCursorKind::SeResize:
4828 c = eCursor_se_resize;
4829 break;
4830 case StyleCursorKind::NeResize:
4831 c = eCursor_ne_resize;
4832 break;
4833 case StyleCursorKind::SwResize:
4834 c = eCursor_sw_resize;
4835 break;
4836 case StyleCursorKind::Copy: // CSS3
4837 c = eCursor_copy;
4838 break;
4839 case StyleCursorKind::Alias:
4840 c = eCursor_alias;
4841 break;
4842 case StyleCursorKind::ContextMenu:
4843 c = eCursor_context_menu;
4844 break;
4845 case StyleCursorKind::Cell:
4846 c = eCursor_cell;
4847 break;
4848 case StyleCursorKind::Grab:
4849 c = eCursor_grab;
4850 break;
4851 case StyleCursorKind::Grabbing:
4852 c = eCursor_grabbing;
4853 break;
4854 case StyleCursorKind::Progress:
4855 c = eCursor_spinning;
4856 break;
4857 case StyleCursorKind::ZoomIn:
4858 c = eCursor_zoom_in;
4859 break;
4860 case StyleCursorKind::ZoomOut:
4861 c = eCursor_zoom_out;
4862 break;
4863 case StyleCursorKind::NotAllowed:
4864 c = eCursor_not_allowed;
4865 break;
4866 case StyleCursorKind::ColResize:
4867 c = eCursor_col_resize;
4868 break;
4869 case StyleCursorKind::RowResize:
4870 c = eCursor_row_resize;
4871 break;
4872 case StyleCursorKind::NoDrop:
4873 c = eCursor_no_drop;
4874 break;
4875 case StyleCursorKind::VerticalText:
4876 c = eCursor_vertical_text;
4877 break;
4878 case StyleCursorKind::AllScroll:
4879 c = eCursor_all_scroll;
4880 break;
4881 case StyleCursorKind::NeswResize:
4882 c = eCursor_nesw_resize;
4883 break;
4884 case StyleCursorKind::NwseResize:
4885 c = eCursor_nwse_resize;
4886 break;
4887 case StyleCursorKind::NsResize:
4888 c = eCursor_ns_resize;
4889 break;
4890 case StyleCursorKind::EwResize:
4891 c = eCursor_ew_resize;
4892 break;
4893 case StyleCursorKind::None:
4894 c = eCursor_none;
4895 break;
4896 default:
4897 MOZ_ASSERT_UNREACHABLE("Unknown cursor kind")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Unknown cursor kind" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4897); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unknown cursor kind" ")"); do { *
((volatile int*)__null) = 4897; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
4898 c = eCursor_standard;
4899 break;
4900 }
4901
4902 uint32_t x = aHotspot ? aHotspot->x.value : 0;
4903 uint32_t y = aHotspot ? aHotspot->y.value : 0;
4904 aWidget->SetCursor(nsIWidget::Cursor{c, aContainer, x, y, aResolution});
4905 return NS_OK;
4906}
4907
4908bool EventStateManager::CursorSettingManagerHasLockedCursor() {
4909 return sCursorSettingManager &&
4910 sCursorSettingManager->mLockCursor != kInvalidCursorKind;
4911}
4912
4913class MOZ_STACK_CLASS ESMEventCB : public EventDispatchingCallback {
4914 public:
4915 explicit ESMEventCB(nsIContent* aTarget) : mTarget(aTarget) {}
4916
4917 MOZ_CAN_RUN_SCRIPT
4918 void HandleEvent(EventChainPostVisitor& aVisitor) override {
4919 if (aVisitor.mPresContext) {
4920 nsIFrame* frame = aVisitor.mPresContext->GetPrimaryFrameFor(mTarget);
4921 if (frame) {
4922 frame->HandleEvent(aVisitor.mPresContext, aVisitor.mEvent->AsGUIEvent(),
4923 &aVisitor.mEventStatus);
4924 }
4925 }
4926 }
4927
4928 nsCOMPtr<nsIContent> mTarget;
4929};
4930
4931static UniquePtr<WidgetMouseEvent> CreateMouseOrPointerWidgetEvent(
4932 WidgetMouseEvent* aMouseEvent, EventMessage aMessage,
4933 EventTarget* aRelatedTarget) {
4934 // This method does not support creating a mouse/pointer button change event
4935 // because of no data about the changing state.
4936 MOZ_ASSERT(aMessage != eMouseDown)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage != eMouseDown)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage != eMouseDown))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aMessage != eMouseDown"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4936); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != eMouseDown"
")"); do { *((volatile int*)__null) = 4936; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4937 MOZ_ASSERT(aMessage != eMouseUp)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage != eMouseUp)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage != eMouseUp))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("aMessage != eMouseUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4937); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != eMouseUp"
")"); do { *((volatile int*)__null) = 4937; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4938 MOZ_ASSERT(aMessage != ePointerDown)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage != ePointerDown)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage != ePointerDown))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aMessage != ePointerDown"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4938); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != ePointerDown"
")"); do { *((volatile int*)__null) = 4938; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4939 MOZ_ASSERT(aMessage != ePointerUp)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage != ePointerUp)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage != ePointerUp))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aMessage != ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4939); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != ePointerUp"
")"); do { *((volatile int*)__null) = 4939; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4940 // This method is currently designed to create the following events.
4941 MOZ_ASSERT(aMessage == eMouseOver || aMessage == eMouseEnter ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4946; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4942 aMessage == eMouseOut || aMessage == eMouseLeave ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4946; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4943 aMessage == ePointerOver || aMessage == ePointerEnter ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4946; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4944 aMessage == ePointerOut || aMessage == ePointerLeave ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4946; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4945 aMessage == eMouseEnterIntoWidget ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4946; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4946 aMessage == eMouseExitFromWidget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4946; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4947
4948 WidgetPointerEvent* sourcePointer = aMouseEvent->AsPointerEvent();
4949 UniquePtr<WidgetMouseEvent> newEvent;
4950 if (sourcePointer) {
4951 AUTO_PROFILER_LABEL("CreateMouseOrPointerWidgetEvent", OTHER)mozilla::AutoProfilerLabel raiiObject4951( "CreateMouseOrPointerWidgetEvent"
, nullptr, JS::ProfilingCategoryPair::OTHER)
;
4952
4953 WidgetPointerEvent* newPointerEvent = new WidgetPointerEvent(
4954 aMouseEvent->IsTrusted(), aMessage, aMouseEvent->mWidget);
4955 newPointerEvent->mIsPrimary = sourcePointer->mIsPrimary;
4956 newPointerEvent->mWidth = sourcePointer->mWidth;
4957 newPointerEvent->mHeight = sourcePointer->mHeight;
4958 newPointerEvent->mInputSource = sourcePointer->mInputSource;
4959
4960 newEvent = WrapUnique(newPointerEvent);
4961 } else {
4962 newEvent = MakeUnique<WidgetMouseEvent>(aMouseEvent->IsTrusted(), aMessage,
4963 aMouseEvent->mWidget,
4964 WidgetMouseEvent::eReal);
4965 }
4966
4967 // Inherit whether the event is synthesized by the test API or not.
4968 // Then, when the event is synthesized by a test API and handled in a remote
4969 // process, it won't be ignored. See PresShell::HandleEvent().
4970 newEvent->mFlags.mIsSynthesizedForTests =
4971 aMouseEvent->mFlags.mIsSynthesizedForTests;
4972
4973 newEvent->mRelatedTarget = aRelatedTarget;
4974 newEvent->mRefPoint = aMouseEvent->mRefPoint;
4975 newEvent->mModifiers = aMouseEvent->mModifiers;
4976 if (!aMouseEvent->mFlags.mDispatchedAtLeastOnce &&
4977 aMouseEvent->InputSourceSupportsHover()) {
4978 // If we synthesize a pointer event or a mouse event from another event
4979 // which changes a button state whose input soucre supports hover state and
4980 // the source event has not been dispatched yet, we should set to the button
4981 // state of the synthesizing event to previous one.
4982 // Note that we don't need to do this if the input source does not support
4983 // hover state because a WPT check the behavior (see below) and the other
4984 // browsers pass the test even though this is inconsistent behavior.
4985 newEvent->mButton =
4986 sourcePointer ? MouseButton::eNotPressed : MouseButton::ePrimary;
4987 if (aMouseEvent->IsPressingButton()) {
4988 // If the source event has not been dispatched into the DOM yet, we
4989 // need to remove the flag which is being pressed.
4990 newEvent->mButtons = static_cast<decltype(WidgetMouseEvent::mButtons)>(
4991 aMouseEvent->mButtons &
4992 ~MouseButtonsFlagToChange(
4993 static_cast<MouseButton>(aMouseEvent->mButton)));
4994 } else if (aMouseEvent->IsReleasingButton()) {
4995 // If the source event has not been dispatched into the DOM yet, we
4996 // need to add the flag which is being released.
4997 newEvent->mButtons = static_cast<decltype(WidgetMouseEvent::mButtons)>(
4998 aMouseEvent->mButtons |
4999 MouseButtonsFlagToChange(
5000 static_cast<MouseButton>(aMouseEvent->mButton)));
5001 } else {
5002 // The source event does not change the buttons state so that we can
5003 // set mButtons value as-is.
5004 newEvent->mButtons = aMouseEvent->mButtons;
5005 }
5006 // Adjust pressure if it does not matches with mButtons.
5007 // FIXME: We may use wrong pressure value if the source event has not been
5008 // dispatched into the DOM yet. However, fixing this requires to store the
5009 // last pressure value somewhere.
5010 if (newEvent->mButtons && aMouseEvent->mPressure == 0) {
5011 newEvent->mPressure = 0.5f;
5012 } else if (!newEvent->mButtons && aMouseEvent->mPressure != 0) {
5013 newEvent->mPressure = 0;
5014 } else {
5015 newEvent->mPressure = aMouseEvent->mPressure;
5016 }
5017 } else {
5018 // If the event has already been dispatched into the tree, web apps has
5019 // already handled the button state change, so the button state of the
5020 // source event has already synced.
5021 // If the input source does not have hover state, we don't need to modify
5022 // the state because the other browsers behave so and tested by
5023 // pointerevent_attributes_nohover_pointers.html even though this is
5024 // different expectation from
5025 // pointerevent_attributes_hoverable_pointers.html, but the other browsers
5026 // pass both of them.
5027 newEvent->mButton = aMouseEvent->mButton;
5028 newEvent->mButtons = aMouseEvent->mButtons;
5029 newEvent->mPressure = aMouseEvent->mPressure;
5030 }
5031
5032 newEvent->mInputSource = aMouseEvent->mInputSource;
5033 newEvent->pointerId = aMouseEvent->pointerId;
5034
5035 return newEvent;
5036}
5037
5038already_AddRefed<nsIWidget>
5039EventStateManager::DispatchMouseOrPointerBoundaryEvent(
5040 WidgetMouseEvent* aMouseEvent, EventMessage aMessage,
5041 nsIContent* aTargetContent, nsIContent* aRelatedContent) {
5042 MOZ_ASSERT(aMessage == eMouseEnter || aMessage == ePointerEnter ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseEnter || aMessage == ePointerEnter
|| aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage
== eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut
|| aMessage == ePointerOut)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseEnter || aMessage
== ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave
|| aMessage == eMouseOver || aMessage == ePointerOver || aMessage
== eMouseOut || aMessage == ePointerOut))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5045); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5045; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5043 aMessage == eMouseLeave || aMessage == ePointerLeave ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseEnter || aMessage == ePointerEnter
|| aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage
== eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut
|| aMessage == ePointerOut)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseEnter || aMessage
== ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave
|| aMessage == eMouseOver || aMessage == ePointerOver || aMessage
== eMouseOut || aMessage == ePointerOut))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5045); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5045; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5044 aMessage == eMouseOver || aMessage == ePointerOver ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseEnter || aMessage == ePointerEnter
|| aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage
== eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut
|| aMessage == ePointerOut)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseEnter || aMessage
== ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave
|| aMessage == eMouseOver || aMessage == ePointerOver || aMessage
== eMouseOut || aMessage == ePointerOut))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5045); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5045; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5045 aMessage == eMouseOut || aMessage == ePointerOut)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseEnter || aMessage == ePointerEnter
|| aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage
== eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut
|| aMessage == ePointerOut)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseEnter || aMessage
== ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave
|| aMessage == eMouseOver || aMessage == ePointerOver || aMessage
== eMouseOut || aMessage == ePointerOut))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5045); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5045; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5046
5047 // https://w3c.github.io/pointerlock/#dom-element-requestpointerlock
5048 // "[Once in the locked state...E]vents that require the concept
5049 // of a mouse cursor must not be dispatched (for example: mouseover,
5050 // mouseout...).
5051 // XXXedgar should we also block pointer events?
5052 if (PointerLockManager::IsLocked() &&
5053 (aMessage == eMouseLeave || aMessage == eMouseEnter ||
5054 aMessage == eMouseOver || aMessage == eMouseOut)) {
5055 mCurrentTargetContent = nullptr;
5056 nsCOMPtr<Element> pointerLockedElement =
5057 PointerLockManager::GetLockedElement();
5058 if (!pointerLockedElement) {
5059 NS_WARNING("Should have pointer locked element, but didn't.")NS_DebugBreak(NS_DEBUG_WARNING, "Should have pointer locked element, but didn't."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5059)
;
5060 return nullptr;
5061 }
5062 nsIFrame* const pointerLockedFrame =
5063 mPresContext->GetPrimaryFrameFor(pointerLockedElement);
5064 if (NS_WARN_IF(!pointerLockedFrame)NS_warn_if_impl(!pointerLockedFrame, "!pointerLockedFrame", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5064)
) {
5065 return nullptr;
5066 }
5067 return do_AddRef(pointerLockedFrame->GetNearestWidget());
5068 }
5069
5070 mCurrentTargetContent = nullptr;
5071
5072 if (!aTargetContent) {
5073 return nullptr;
5074 }
5075
5076 // Store the widget before dispatching the event because some event listeners
5077 // of the dispatching event may cause reframe the target or remove the target
5078 // from the tree.
5079 nsCOMPtr<nsIWidget> targetWidget;
5080 if (nsIFrame* const targetFrame =
5081 mPresContext->GetPrimaryFrameFor(aTargetContent)) {
5082 targetWidget = targetFrame->GetNearestWidget();
5083 }
5084
5085 nsCOMPtr<nsIContent> targetContent = aTargetContent;
5086 nsCOMPtr<nsIContent> relatedContent = aRelatedContent;
5087
5088 UniquePtr<WidgetMouseEvent> dispatchEvent =
5089 CreateMouseOrPointerWidgetEvent(aMouseEvent, aMessage, relatedContent);
5090
5091 AutoWeakFrame previousTarget = mCurrentTarget;
5092 mCurrentTargetContent = targetContent;
5093
5094 nsEventStatus status = nsEventStatus_eIgnore;
5095 ESMEventCB callback(targetContent);
5096 RefPtr<nsPresContext> presContext = mPresContext;
5097 EventDispatcher::Dispatch(targetContent, presContext, dispatchEvent.get(),
5098 nullptr, &status, &callback);
5099
5100 if (mPresContext) {
5101 // If we are entering/leaving remote content, dispatch a mouse enter/exit
5102 // event to the remote frame.
5103 if (IsTopLevelRemoteTarget(targetContent)) {
5104 if (aMessage == eMouseOut) {
5105 // For remote content, send a puppet widget mouse exit event.
5106 UniquePtr<WidgetMouseEvent> remoteEvent =
5107 CreateMouseOrPointerWidgetEvent(aMouseEvent, eMouseExitFromWidget,
5108 relatedContent);
5109 remoteEvent->mExitFrom = Some(WidgetMouseEvent::ePuppet);
5110
5111 // mCurrentTarget is set to the new target, so we must reset it to the
5112 // old target and then dispatch a cross-process event. (mCurrentTarget
5113 // will be set back below.) HandleCrossProcessEvent will query for the
5114 // proper target via GetEventTarget which will return mCurrentTarget.
5115 mCurrentTarget = mPresContext->GetPrimaryFrameFor(targetContent);
5116 HandleCrossProcessEvent(remoteEvent.get(), &status);
5117 } else if (aMessage == eMouseOver) {
5118 UniquePtr<WidgetMouseEvent> remoteEvent =
5119 CreateMouseOrPointerWidgetEvent(aMouseEvent, eMouseEnterIntoWidget,
5120 relatedContent);
5121 HandleCrossProcessEvent(remoteEvent.get(), &status);
5122 }
5123 }
5124 }
5125
5126 mCurrentTargetContent = nullptr;
5127 mCurrentTarget = previousTarget;
5128
5129 return targetWidget.forget();
5130}
5131
5132static nsIContent* FindCommonAncestor(nsIContent* aNode1, nsIContent* aNode2) {
5133 if (!aNode1 || !aNode2) {
5134 return nullptr;
5135 }
5136 return nsContentUtils::GetCommonFlattenedTreeAncestor(aNode1, aNode2);
5137}
5138
5139class EnterLeaveDispatcher {
5140 public:
5141 EnterLeaveDispatcher(EventStateManager* aESM, nsIContent* aTarget,
5142 nsIContent* aRelatedTarget,
5143 WidgetMouseEvent* aMouseEvent,
5144 EventMessage aEventMessage)
5145 : mESM(aESM), mMouseEvent(aMouseEvent), mEventMessage(aEventMessage) {
5146 nsPIDOMWindowInner* win =
5147 aTarget ? aTarget->OwnerDoc()->GetInnerWindow() : nullptr;
5148 if (aMouseEvent->AsPointerEvent()
5149 ? win && win->HasPointerEnterLeaveEventListeners()
5150 : win && win->HasMouseEnterLeaveEventListeners()) {
5151 mRelatedTarget =
5152 aRelatedTarget ? aRelatedTarget->FindFirstNonChromeOnlyAccessContent()
5153 : nullptr;
5154 nsINode* commonParent = FindCommonAncestor(aTarget, aRelatedTarget);
5155 nsIContent* current = aTarget;
5156 // Note, it is ok if commonParent is null!
5157 while (current && current != commonParent) {
5158 if (!current->ChromeOnlyAccess()) {
5159 mTargets.AppendObject(current);
5160 }
5161 // mouseenter/leave is fired only on elements.
5162 current = current->GetFlattenedTreeParent();
5163 }
5164 }
5165 }
5166
5167 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
5168 MOZ_CAN_RUN_SCRIPT_BOUNDARY void Dispatch() {
5169 if (mEventMessage == eMouseEnter || mEventMessage == ePointerEnter) {
5170 for (int32_t i = mTargets.Count() - 1; i >= 0; --i) {
5171 nsCOMPtr<nsIWidget> widget = mESM->DispatchMouseOrPointerBoundaryEvent(
5172 mMouseEvent, mEventMessage, MOZ_KnownLive(mTargets[i])(mTargets[i]),
5173 mRelatedTarget);
5174 }
5175 } else {
5176 for (int32_t i = 0; i < mTargets.Count(); ++i) {
5177 nsCOMPtr<nsIWidget> widget = mESM->DispatchMouseOrPointerBoundaryEvent(
5178 mMouseEvent, mEventMessage, MOZ_KnownLive(mTargets[i])(mTargets[i]),
5179 mRelatedTarget);
5180 }
5181 }
5182 }
5183
5184 // Nothing overwrites anything after constructor. Please remove MOZ_KnownLive
5185 // and MOZ_KNOWN_LIVE if anything marked as such becomes mutable.
5186 const RefPtr<EventStateManager> mESM;
5187 nsCOMArray<nsIContent> mTargets;
5188 MOZ_KNOWN_LIVE nsCOMPtr<nsIContent> mRelatedTarget;
5189 WidgetMouseEvent* mMouseEvent;
5190 EventMessage mEventMessage;
5191};
5192
5193void EventStateManager::NotifyMouseOut(WidgetMouseEvent* aMouseEvent,
5194 nsIContent* aMovingInto) {
5195 const bool isPointer = aMouseEvent->mClass == ePointerEventClass;
5196 LogModule* const logModule =
5197 isPointer ? sPointerBoundaryLog : sMouseBoundaryLog;
5198
5199 RefPtr<OverOutElementsWrapper> wrapper = GetWrapperByEventID(aMouseEvent);
5200
5201 // If there is no deepest "leave" event target, that means the last "over"
5202 // target has already been removed from the tree. Therefore, checking only
5203 // the "leave" event target is enough.
5204 if (!wrapper || !wrapper->GetDeepestLeaveEventTarget()) {
5205 return;
5206 }
5207 // Before firing "out" and/or "leave" events, check for recursion
5208 if (wrapper->IsDispatchingOutEventOnLastOverEventTarget()) {
5209 return;
5210 }
5211
5212 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOut: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5213 ("NotifyMouseOut: the source event is %s (IsReal()=%s)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOut: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5214 ToChar(aMouseEvent->mMessage),do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOut: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5215 aMouseEvent->IsReal() ? "true" : "false"))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOut: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
;
5216
5217 // XXX If a content node is a container of remove content, it should be
5218 // replaced with them and its children should not be visible. Therefore,
5219 // if the deepest "enter" target is not the last "over" target, i.e., the
5220 // last "over" target has been removed from the DOM tree, it means that the
5221 // child/descendant was not replaced by remote content. So,
5222 // wrapper->GetOutEventTaget() may be enough here.
5223 if (RefPtr<nsFrameLoaderOwner> flo =
5224 do_QueryObject(wrapper->GetDeepestLeaveEventTarget())) {
5225 if (BrowsingContext* bc = flo->GetExtantBrowsingContext()) {
5226 if (nsIDocShell* docshell = bc->GetDocShell()) {
5227 if (RefPtr<nsPresContext> presContext = docshell->GetPresContext()) {
5228 EventStateManager* kidESM = presContext->EventStateManager();
5229 // Not moving into any element in this subdocument
5230 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying child EventStateManager (%p) of \"out\" "
"event...", kidESM); } } while (0)
5231 ("Notifying child EventStateManager (%p) of \"out\" "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying child EventStateManager (%p) of \"out\" "
"event...", kidESM); } } while (0)
5232 "event...",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying child EventStateManager (%p) of \"out\" "
"event...", kidESM); } } while (0)
5233 kidESM))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying child EventStateManager (%p) of \"out\" "
"event...", kidESM); } } while (0)
;
5234 kidESM->NotifyMouseOut(aMouseEvent, nullptr);
5235 }
5236 }
5237 }
5238 }
5239 // That could have caused DOM events which could wreak havoc. Reverify
5240 // things and be careful.
5241 if (!wrapper->GetDeepestLeaveEventTarget()) {
5242 return;
5243 }
5244
5245 wrapper->WillDispatchOutAndOrLeaveEvent();
5246
5247 // Don't touch hover state if aMovingInto is non-null. Caller will update
5248 // hover state itself, and we have optimizations for hover switching between
5249 // two nearby elements both deep in the DOM tree that would be defeated by
5250 // switching the hover state to null here.
5251 if (!aMovingInto && !isPointer) {
5252 // Unset :hover
5253 SetContentState(nullptr, ElementState::HOVER);
5254 }
5255
5256 EnterLeaveDispatcher leaveDispatcher(
5257 this, wrapper->GetDeepestLeaveEventTarget(), aMovingInto, aMouseEvent,
5258 isPointer ? ePointerLeave : eMouseLeave);
5259
5260 // "out" events hould be fired only when the deepest "leave" event target
5261 // is the last "over" event target.
5262 if (nsCOMPtr<nsIContent> outEventTarget = wrapper->GetOutEventTarget()) {
5263 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
5264 ("Dispatching %s event to %s (%p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
5265 isPointer ? "ePointerOut" : "eMouseOut",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
5266 outEventTarget ? ToString(*outEventTarget).c_str() : "nullptr",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
5267 outEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
;
5268 nsCOMPtr<nsIWidget> widget = DispatchMouseOrPointerBoundaryEvent(
5269 aMouseEvent, isPointer ? ePointerOut : eMouseOut, outEventTarget,
5270 aMovingInto);
5271 }
5272
5273 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5274 ("Dispatching %s event to %s (%p) and its ancestors",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5275 isPointer ? "ePointerLeave" : "eMouseLeave",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5276 wrapper->GetDeepestLeaveEventTarget()do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5277 ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str()do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5278 : "nullptr",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5279 wrapper->GetDeepestLeaveEventTarget()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
;
5280 leaveDispatcher.Dispatch();
5281
5282 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"out\" and/or \"leave\" events"
); } } while (0)
5283 ("Dispatched \"out\" and/or \"leave\" events"))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"out\" and/or \"leave\" events"
); } } while (0)
;
5284 wrapper->DidDispatchOutAndOrLeaveEvent();
5285}
5286
5287void EventStateManager::RecomputeMouseEnterStateForRemoteFrame(
5288 Element& aElement) {
5289 if (!mMouseEnterLeaveHelper ||
5290 mMouseEnterLeaveHelper->GetDeepestLeaveEventTarget() != &aElement) {
5291 return;
5292 }
5293
5294 if (BrowserParent* remote = BrowserParent::GetFrom(&aElement)) {
5295 remote->MouseEnterIntoWidget();
5296 }
5297}
5298
5299void EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
5300 nsIContent* aContent) {
5301 NS_ASSERTION(aContent, "Mouse must be over something")do { if (!(aContent)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Mouse must be over something"
, "aContent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5301); MOZ_PretendNoReturn(); } } while (0)
;
5302
5303 const bool isPointer = aMouseEvent->mClass == ePointerEventClass;
5304 LogModule* const logModule =
5305 isPointer ? sPointerBoundaryLog : sMouseBoundaryLog;
5306
5307 RefPtr<OverOutElementsWrapper> wrapper = GetWrapperByEventID(aMouseEvent);
5308
5309 // If we have next "out" event target and it's the new "over" target, we don't
5310 // need to dispatch "out" nor "enter" event.
5311 if (!wrapper || aContent == wrapper->GetOutEventTarget()) {
5312 return;
5313 }
5314
5315 // Before firing "over" and "enter" events, check for recursion
5316 if (wrapper->IsDispatchingOverEventOn(aContent)) {
5317 return;
5318 }
5319
5320 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOver: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5321 ("NotifyMouseOver: the source event is %s (IsReal()=%s)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOver: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5322 ToChar(aMouseEvent->mMessage),do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOver: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5323 aMouseEvent->IsReal() ? "true" : "false"))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOver: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
;
5324
5325 // Check to see if we're a subdocument and if so update the parent
5326 // document's ESM state to indicate that the mouse is over the
5327 // content associated with our subdocument.
5328 EnsureDocument(mPresContext);
5329 if (Document* parentDoc = mDocument->GetInProcessParentDocument()) {
5330 if (nsCOMPtr<nsIContent> docContent = mDocument->GetEmbedderElement()) {
5331 if (PresShell* parentPresShell = parentDoc->GetPresShell()) {
5332 RefPtr<EventStateManager> parentESM =
5333 parentPresShell->GetPresContext()->EventStateManager();
5334 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying parent EventStateManager (%p) of \"over\" "
"event...", parentESM.get()); } } while (0)
5335 ("Notifying parent EventStateManager (%p) of \"over\" "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying parent EventStateManager (%p) of \"over\" "
"event...", parentESM.get()); } } while (0)
5336 "event...",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying parent EventStateManager (%p) of \"over\" "
"event...", parentESM.get()); } } while (0)
5337 parentESM.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying parent EventStateManager (%p) of \"over\" "
"event...", parentESM.get()); } } while (0)
;
5338 parentESM->NotifyMouseOver(aMouseEvent, docContent);
5339 }
5340 }
5341 }
5342 // Firing the DOM event in the parent document could cause all kinds
5343 // of havoc. Reverify and take care.
5344 if (aContent == wrapper->GetOutEventTarget()) {
5345 return;
5346 }
5347
5348 // Remember the deepest leave event target as the related content for the
5349 // DispatchMouseOrPointerBoundaryEvent() call below, since NotifyMouseOut()
5350 // resets it, bug 298477.
5351 nsCOMPtr<nsIContent> deepestLeaveEventTarget =
5352 wrapper->GetDeepestLeaveEventTarget();
5353
5354 EnterLeaveDispatcher enterDispatcher(this, aContent, deepestLeaveEventTarget,
5355 aMouseEvent,
5356 isPointer ? ePointerEnter : eMouseEnter);
5357
5358 if (!isPointer) {
5359 SetContentState(aContent, ElementState::HOVER);
5360 }
5361
5362 NotifyMouseOut(aMouseEvent, aContent);
5363
5364 wrapper->WillDispatchOverAndEnterEvent(aContent);
5365
5366 // Fire mouseover
5367 // XXX If aContent has already been removed from the DOM tree, what should we
5368 // do? At least, dispatching `mouseover` on it is odd.
5369 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOver" : "eMoustOver", aContent ? ToString(*aContent
).c_str() : "nullptr", aContent); } } while (0)
5370 ("Dispatching %s event to %s (%p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOver" : "eMoustOver", aContent ? ToString(*aContent
).c_str() : "nullptr", aContent); } } while (0)
5371 isPointer ? "ePointerOver" : "eMoustOver",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOver" : "eMoustOver", aContent ? ToString(*aContent
).c_str() : "nullptr", aContent); } } while (0)
5372 aContent ? ToString(*aContent).c_str() : "nullptr", aContent))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOver" : "eMoustOver", aContent ? ToString(*aContent
).c_str() : "nullptr", aContent); } } while (0)
;
5373 nsCOMPtr<nsIWidget> targetWidget = DispatchMouseOrPointerBoundaryEvent(
5374 aMouseEvent, isPointer ? ePointerOver : eMouseOver, aContent,
5375 deepestLeaveEventTarget);
5376
5377 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerEnter" : "eMouseEnter", aContent ? ToString
(*aContent).c_str() : "nullptr", aContent); } } while (0)
5378 ("Dispatching %s event to %s (%p) and its ancestors",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerEnter" : "eMouseEnter", aContent ? ToString
(*aContent).c_str() : "nullptr", aContent); } } while (0)
5379 isPointer ? "ePointerEnter" : "eMouseEnter",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerEnter" : "eMouseEnter", aContent ? ToString
(*aContent).c_str() : "nullptr", aContent); } } while (0)
5380 aContent ? ToString(*aContent).c_str() : "nullptr", aContent))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerEnter" : "eMouseEnter", aContent ? ToString
(*aContent).c_str() : "nullptr", aContent); } } while (0)
;
5381 enterDispatcher.Dispatch();
5382
5383 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"over\" and \"enter\" events (the original \"over\" "
"event target was in the document %p, and now in %p)", aContent
->GetComposedDoc(), mDocument.get()); } } while (0)
5384 ("Dispatched \"over\" and \"enter\" events (the original \"over\" "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"over\" and \"enter\" events (the original \"over\" "
"event target was in the document %p, and now in %p)", aContent
->GetComposedDoc(), mDocument.get()); } } while (0)
5385 "event target was in the document %p, and now in %p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"over\" and \"enter\" events (the original \"over\" "
"event target was in the document %p, and now in %p)", aContent
->GetComposedDoc(), mDocument.get()); } } while (0)
5386 aContent->GetComposedDoc(), mDocument.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"over\" and \"enter\" events (the original \"over\" "
"event target was in the document %p, and now in %p)", aContent
->GetComposedDoc(), mDocument.get()); } } while (0)
;
5387 wrapper->DidDispatchOverAndEnterEvent(
5388 aContent->GetComposedDoc() == mDocument ? aContent : nullptr,
5389 targetWidget);
5390}
5391
5392// Returns the center point of the window's client area. This is
5393// in widget coordinates, i.e. relative to the widget's top-left
5394// corner, not in screen coordinates, the same units that UIEvent::
5395// refpoint is in. It may not be the exact center of the window if
5396// the platform requires rounding the coordinate.
5397static LayoutDeviceIntPoint GetWindowClientRectCenter(nsIWidget* aWidget) {
5398 NS_ENSURE_TRUE(aWidget, LayoutDeviceIntPoint(0, 0))do { if ((__builtin_expect(!!(!(aWidget)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aWidget" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5398); return LayoutDeviceIntPoint(0, 0); } } while (false)
;
5399
5400 LayoutDeviceIntRect rect = aWidget->GetClientBounds();
5401 LayoutDeviceIntPoint point(rect.width / 2, rect.height / 2);
5402 int32_t round = aWidget->RoundsWidgetCoordinatesTo();
5403 point.x = point.x / round * round;
5404 point.y = point.y / round * round;
5405 return point;
5406}
5407
5408void EventStateManager::GeneratePointerEnterExit(EventMessage aMessage,
5409 WidgetMouseEvent* aEvent) {
5410 WidgetPointerEvent pointerEvent(*aEvent);
5411 pointerEvent.mMessage = aMessage;
5412 GenerateMouseEnterExit(&pointerEvent);
5413}
5414
5415/* static */
5416void EventStateManager::UpdateLastRefPointOfMouseEvent(
5417 WidgetMouseEvent* aMouseEvent) {
5418 if (aMouseEvent->mMessage != eMouseMove &&
5419 aMouseEvent->mMessage != ePointerMove) {
5420 return;
5421 }
5422
5423 // Mouse movement is reported on the MouseEvent.movement{X,Y} fields.
5424 // Movement is calculated in UIEvent::GetMovementPoint() as:
5425 // previous_mousemove_mRefPoint - current_mousemove_mRefPoint.
5426 if (PointerLockManager::IsLocked() && aMouseEvent->mWidget) {
5427 // The pointer is locked. If the pointer is not located at the center of
5428 // the window, dispatch a synthetic mousemove to return the pointer there.
5429 // Doing this between "real" pointer moves gives the impression that the
5430 // (locked) pointer can continue moving and won't stop at the screen
5431 // boundary. We cancel the synthetic event so that we don't end up
5432 // dispatching the centering move event to content.
5433 aMouseEvent->mLastRefPoint =
5434 GetWindowClientRectCenter(aMouseEvent->mWidget);
5435
5436 } else if (sLastRefPoint == kInvalidRefPoint) {
5437 // We don't have a valid previous mousemove mRefPoint. This is either
5438 // the first move we've encountered, or the mouse has just re-entered
5439 // the application window. We should report (0,0) movement for this
5440 // case, so make the current and previous mRefPoints the same.
5441 aMouseEvent->mLastRefPoint = aMouseEvent->mRefPoint;
5442 } else {
5443 aMouseEvent->mLastRefPoint = sLastRefPoint;
5444 }
5445}
5446
5447/* static */
5448void EventStateManager::ResetPointerToWindowCenterWhilePointerLocked(
5449 WidgetMouseEvent* aMouseEvent) {
5450 MOZ_ASSERT(PointerLockManager::IsLocked())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(PointerLockManager::IsLocked())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(PointerLockManager::IsLocked
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("PointerLockManager::IsLocked()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5450); AnnotateMozCrashReason("MOZ_ASSERT" "(" "PointerLockManager::IsLocked()"
")"); do { *((volatile int*)__null) = 5450; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5451 if ((aMouseEvent->mMessage != eMouseMove &&
5452 aMouseEvent->mMessage != ePointerMove) ||
5453 !aMouseEvent->mWidget) {
5454 return;
5455 }
5456
5457 // We generate pointermove from mousemove event, so only synthesize native
5458 // mouse move and update sSynthCenteringPoint by mousemove event.
5459 bool updateSynthCenteringPoint = aMouseEvent->mMessage == eMouseMove;
5460
5461 // The pointer is locked. If the pointer is not located at the center of
5462 // the window, dispatch a synthetic mousemove to return the pointer there.
5463 // Doing this between "real" pointer moves gives the impression that the
5464 // (locked) pointer can continue moving and won't stop at the screen
5465 // boundary. We cancel the synthetic event so that we don't end up
5466 // dispatching the centering move event to content.
5467 LayoutDeviceIntPoint center = GetWindowClientRectCenter(aMouseEvent->mWidget);
5468
5469 if (aMouseEvent->mRefPoint != center && updateSynthCenteringPoint) {
5470 // Mouse move doesn't finish at the center of the window. Dispatch a
5471 // synthetic native mouse event to move the pointer back to the center
5472 // of the window, to faciliate more movement. But first, record that
5473 // we've dispatched a synthetic mouse movement, so we can cancel it
5474 // in the other branch here.
5475 sSynthCenteringPoint = center;
5476 // XXX Once we fix XXX comments in SetPointerLock about this API, we could
5477 // restrict that this API works only in the automation mode or in the
5478 // pointer locked situation.
5479 aMouseEvent->mWidget->SynthesizeNativeMouseMove(
5480 center + aMouseEvent->mWidget->WidgetToScreenOffset(), nullptr);
5481 } else if (aMouseEvent->mRefPoint == sSynthCenteringPoint) {
5482 // This is the "synthetic native" event we dispatched to re-center the
5483 // pointer. Cancel it so we don't expose the centering move to content.
5484 aMouseEvent->StopPropagation();
5485 // Clear sSynthCenteringPoint so we don't cancel other events
5486 // targeted at the center.
5487 if (updateSynthCenteringPoint) {
5488 sSynthCenteringPoint = kInvalidRefPoint;
5489 }
5490 }
5491}
5492
5493/* static */
5494void EventStateManager::UpdateLastPointerPosition(
5495 WidgetMouseEvent* aMouseEvent) {
5496 if (aMouseEvent->mMessage != eMouseMove) {
5497 return;
5498 }
5499 sLastRefPoint = aMouseEvent->mRefPoint;
5500}
5501
5502void EventStateManager::GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent) {
5503 EnsureDocument(mPresContext);
5504 if (!mDocument) return;
5505
5506 // Hold onto old target content through the event and reset after.
5507 nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
5508
5509 switch (aMouseEvent->mMessage) {
5510 case eMouseMove:
5511 case ePointerMove:
5512 case ePointerDown:
5513 case ePointerGotCapture: {
5514 // Get the target content target (mousemove target == mouseover target)
5515 nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
5516 if (!targetElement) {
5517 // We're always over the document root, even if we're only
5518 // over dead space in a page (whose frame is not associated with
5519 // any content) or in print preview dead space
5520 targetElement = mDocument->GetRootElement();
5521 }
5522 if (targetElement) {
5523 NotifyMouseOver(aMouseEvent, targetElement);
5524 }
5525 break;
5526 }
5527 case ePointerUp: {
5528 if (!StaticPrefs::
5529 dom_events_mouse_pointer_boundary_keep_enter_targets_after_over_target_removed()) {
5530 // In the legacy mode, we should do nothing if the event has not been
5531 // dispatched yet (i.e., called by PreHandleEvent).
5532 // On the other hand, if the event was dispatched (i.e., called by
5533 // PostEventHandler), we need to dispatch "pointerout" and
5534 // "pointerleave" events because the pointer will be removed
5535 // (invalidated) by the "pointerup" operation.
5536 if (!aMouseEvent->mFlags.mDispatchedAtLeastOnce) {
5537 break;
5538 }
5539 MOZ_ASSERT(!aMouseEvent->InputSourceSupportsHover())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aMouseEvent->InputSourceSupportsHover())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aMouseEvent->InputSourceSupportsHover()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aMouseEvent->InputSourceSupportsHover()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5539); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aMouseEvent->InputSourceSupportsHover()"
")"); do { *((volatile int*)__null) = 5539; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5540 // Get the target content target (pointermove target == pointerover
5541 // target)
5542 nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
5543 if (!targetElement) {
5544 // We're always over the document root, even if we're only
5545 // over dead space in a page (whose frame is not associated with
5546 // any content) or in print preview dead space
5547 targetElement = mDocument->GetRootElement();
5548 }
5549 if (targetElement) {
5550 // XXX It's odd to override the `pointerout` event target with the
5551 // content under the pointer or something because it may have never
5552 // received `pointerover` event. I think that this was required for
5553 // digitizer which supports hover state (bug 985511). However, this
5554 // is now not called at ePointerUp if the device supports hover.
5555 RefPtr<OverOutElementsWrapper> helper =
5556 GetWrapperByEventID(aMouseEvent);
5557 if (helper) {
5558 helper->OverrideOverEventTarget(targetElement);
5559 }
5560 NotifyMouseOut(aMouseEvent, nullptr);
5561 }
5562 break;
5563 }
5564
5565 if (aMouseEvent->mFlags.mDispatchedAtLeastOnce) {
5566 // If we've already dispatched the pointerup event caused by
5567 // non-hoverable input device like touch, we need to synthesize
5568 // pointerout and pointerleave events because the poiner is valid only
5569 // while it's "down".
5570 if (!aMouseEvent->InputSourceSupportsHover()) {
5571 NotifyMouseOut(aMouseEvent, nullptr);
5572 }
5573 break;
5574 }
5575
5576 // If we're going to dispatch the pointerup event and the element under
5577 // the pointer is changed from the previous pointer event dispatching, we
5578 // need to dispatch pointer boundary events. If the pointing device is
5579 // hoverable, we always need to do it. Otherwise, an element captures the
5580 // pointer by default. If so, we don't need the boundary events, but if
5581 // the capture has already been released, e.g., by the capturing element
5582 // is removed, we need to dispatch the pointer boundary event the same
5583 // way as with hoverable pointer.
5584 if (aMouseEvent->InputSourceSupportsHover() ||
5585 !PointerEventHandler::GetPointerCapturingElement(
5586 aMouseEvent->pointerId)) {
5587 nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
5588 if (!targetElement) {
5589 targetElement = mDocument->GetRootElement();
5590 }
5591 if (targetElement) {
5592 NotifyMouseOver(aMouseEvent, targetElement);
5593 }
5594 break;
5595 }
5596 break;
5597 }
5598 case ePointerLeave:
5599 case ePointerCancel:
5600 case eMouseExitFromWidget: {
5601 // This is actually the window mouse exit or pointer leave event. We're
5602 // not moving into any new element.
5603
5604 RefPtr<OverOutElementsWrapper> helper = GetWrapperByEventID(aMouseEvent);
5605 if (helper) {
5606 nsCOMPtr<nsIWidget> lastOverWidget = helper->GetLastOverWidget();
5607 if (lastOverWidget &&
5608 nsContentUtils::GetTopLevelWidget(aMouseEvent->mWidget) !=
5609 nsContentUtils::GetTopLevelWidget(lastOverWidget)) {
5610 // the Mouse/PointerOut event widget doesn't have same top widget with
5611 // the last over event target, it's a spurious event for the frame for
5612 // the target.
5613 break;
5614 }
5615 }
5616
5617 // Reset sLastRefPoint, so that we'll know not to report any
5618 // movement the next time we re-enter the window.
5619 sLastRefPoint = kInvalidRefPoint;
5620
5621 NotifyMouseOut(aMouseEvent, nullptr);
5622 break;
5623 }
5624 default:
5625 break;
5626 }
5627
5628 // reset mCurretTargetContent to what it was
5629 mCurrentTargetContent = targetBeforeEvent;
5630}
5631
5632OverOutElementsWrapper* EventStateManager::GetWrapperByEventID(
5633 WidgetMouseEvent* aEvent) {
5634 WidgetPointerEvent* pointer = aEvent->AsPointerEvent();
5635 if (!pointer) {
5636 MOZ_ASSERT(aEvent->AsMouseEvent() != nullptr)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->AsMouseEvent() != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->AsMouseEvent() !=
nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aEvent->AsMouseEvent() != nullptr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5636); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->AsMouseEvent() != nullptr"
")"); do { *((volatile int*)__null) = 5636; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5637 if (!mMouseEnterLeaveHelper) {
5638 mMouseEnterLeaveHelper = new OverOutElementsWrapper(
5639 OverOutElementsWrapper::BoundaryEventType::Mouse);
5640 }
5641 return mMouseEnterLeaveHelper;
5642 }
5643 return mPointersEnterLeaveHelper.GetOrInsertNew(
5644 pointer->pointerId, OverOutElementsWrapper::BoundaryEventType::Pointer);
5645}
5646
5647/* static */
5648void EventStateManager::SetPointerLock(nsIWidget* aWidget,
5649 nsPresContext* aPresContext) {
5650 // Reset mouse wheel transaction
5651 WheelTransaction::EndTransaction();
5652
5653 // Deal with DnD events
5654 nsCOMPtr<nsIDragService> dragService =
5655 do_GetService("@mozilla.org/widget/dragservice;1");
5656
5657 if (PointerLockManager::IsLocked()) {
5658 MOZ_ASSERT(aWidget, "Locking pointer requires a widget")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aWidget))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aWidget" " (" "Locking pointer requires a widget"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5658); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWidget" ") ("
"Locking pointer requires a widget" ")"); do { *((volatile int
*)__null) = 5658; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
5659 MOZ_ASSERT(aPresContext, "Locking pointer requires a presContext")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresContext))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPresContext" " ("
"Locking pointer requires a presContext" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5659); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresContext"
") (" "Locking pointer requires a presContext" ")"); do { *(
(volatile int*)__null) = 5659; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
5660
5661 // Release all pointer capture when a pointer lock is successfully applied
5662 // on an element.
5663 PointerEventHandler::ReleaseAllPointerCapture();
5664
5665 // Store the last known ref point so we can reposition the pointer after
5666 // unlock.
5667 sPreLockScreenPoint = LayoutDeviceIntPoint::Round(
5668 sLastScreenPoint * aPresContext->CSSToDevPixelScale());
5669
5670 // Fire a synthetic mouse move to ensure event state is updated. We first
5671 // set the mouse to the center of the window, so that the mouse event
5672 // doesn't report any movement.
5673 // XXX Cannot we do synthesize the native mousemove in the parent process
5674 // with calling LockNativePointer below? Then, we could make this API
5675 // work only in the automation mode.
5676 sLastRefPoint = GetWindowClientRectCenter(aWidget);
5677 aWidget->SynthesizeNativeMouseMove(
5678 sLastRefPoint + aWidget->WidgetToScreenOffset(), nullptr);
5679
5680 // Suppress DnD
5681 if (dragService) {
5682 dragService->Suppress();
5683 }
5684
5685 // Activate native pointer lock on platforms where it is required (Wayland)
5686 aWidget->LockNativePointer();
5687 } else {
5688 if (aWidget) {
5689 // Deactivate native pointer lock on platforms where it is required
5690 aWidget->UnlockNativePointer();
5691 }
5692
5693 // Reset SynthCenteringPoint to invalid so that next time we start
5694 // locking pointer, it has its initial value.
5695 sSynthCenteringPoint = kInvalidRefPoint;
5696 if (aWidget) {
5697 // Unlocking, so return pointer to the original position by firing a
5698 // synthetic mouse event. We first reset sLastRefPoint to its
5699 // pre-pointerlock position, so that the synthetic mouse event reports
5700 // no movement.
5701 sLastRefPoint = sPreLockScreenPoint - aWidget->WidgetToScreenOffset();
5702 // XXX Cannot we do synthesize the native mousemove in the parent process
5703 // with calling `UnlockNativePointer` above? Then, we could make this
5704 // API work only in the automation mode.
5705 aWidget->SynthesizeNativeMouseMove(sPreLockScreenPoint, nullptr);
5706 }
5707
5708 // Unsuppress DnD
5709 if (dragService) {
5710 dragService->Unsuppress();
5711 }
5712 }
5713}
5714
5715void EventStateManager::GenerateDragDropEnterExit(nsPresContext* aPresContext,
5716 WidgetDragEvent* aDragEvent) {
5717 // Hold onto old target content through the event and reset after.
5718 nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
5719
5720 switch (aDragEvent->mMessage) {
5721 case eDragOver: {
5722 // when dragging from one frame to another, events are fired in the
5723 // order: dragexit, dragenter, dragleave
5724 if (sLastDragOverFrame != mCurrentTarget) {
5725 // We'll need the content, too, to check if it changed separately from
5726 // the frames.
5727 nsCOMPtr<nsIContent> lastContent;
5728 nsCOMPtr<nsIContent> targetContent;
5729 mCurrentTarget->GetContentForEvent(aDragEvent,
5730 getter_AddRefs(targetContent));
5731 if (targetContent && targetContent->IsText()) {
5732 targetContent = targetContent->GetFlattenedTreeParent();
5733 }
5734
5735 if (sLastDragOverFrame) {
5736 // The frame has changed but the content may not have. Check before
5737 // dispatching to content
5738 sLastDragOverFrame->GetContentForEvent(aDragEvent,
5739 getter_AddRefs(lastContent));
5740 if (lastContent && lastContent->IsText()) {
5741 lastContent = lastContent->GetFlattenedTreeParent();
5742 }
5743
5744 RefPtr<nsPresContext> presContext = sLastDragOverFrame->PresContext();
5745 FireDragEnterOrExit(presContext, aDragEvent, eDragExit, targetContent,
5746 lastContent, sLastDragOverFrame);
5747 nsIContent* target = sLastDragOverFrame
5748 ? sLastDragOverFrame.GetFrame()->GetContent()
5749 : nullptr;
5750 // XXXedgar, look like we need to consider fission OOP iframe, too.
5751 if (IsTopLevelRemoteTarget(target)) {
5752 // Dragging something and moving from web content to chrome only
5753 // fires dragexit and dragleave to xul:browser. We have to forward
5754 // dragexit to sLastDragOverFrame when its content is a remote
5755 // target. We don't forward dragleave since it's generated from
5756 // dragexit.
5757 WidgetDragEvent remoteEvent(aDragEvent->IsTrusted(), eDragExit,
5758 aDragEvent->mWidget);
5759 remoteEvent.AssignDragEventData(*aDragEvent, true);
5760 remoteEvent.mFlags.mIsSynthesizedForTests =
5761 aDragEvent->mFlags.mIsSynthesizedForTests;
5762 nsEventStatus remoteStatus = nsEventStatus_eIgnore;
5763 HandleCrossProcessEvent(&remoteEvent, &remoteStatus);
5764 }
5765 }
5766
5767 AutoWeakFrame currentTraget = mCurrentTarget;
5768 FireDragEnterOrExit(aPresContext, aDragEvent, eDragEnter, lastContent,
5769 targetContent, currentTraget);
5770
5771 if (sLastDragOverFrame) {
5772 RefPtr<nsPresContext> presContext = sLastDragOverFrame->PresContext();
5773 FireDragEnterOrExit(presContext, aDragEvent, eDragLeave,
5774 targetContent, lastContent, sLastDragOverFrame);
5775 }
5776
5777 sLastDragOverFrame = mCurrentTarget;
5778 }
5779 } break;
5780
5781 case eDragExit: {
5782 // This is actually the window mouse exit event.
5783 if (sLastDragOverFrame) {
5784 nsCOMPtr<nsIContent> lastContent;
5785 sLastDragOverFrame->GetContentForEvent(aDragEvent,
5786 getter_AddRefs(lastContent));
5787
5788 RefPtr<nsPresContext> lastDragOverFramePresContext =
5789 sLastDragOverFrame->PresContext();
5790 FireDragEnterOrExit(lastDragOverFramePresContext, aDragEvent, eDragExit,
5791 nullptr, lastContent, sLastDragOverFrame);
5792 FireDragEnterOrExit(lastDragOverFramePresContext, aDragEvent,
5793 eDragLeave, nullptr, lastContent,
5794 sLastDragOverFrame);
5795
5796 sLastDragOverFrame = nullptr;
5797 }
5798 } break;
5799
5800 default:
5801 break;
5802 }
5803
5804 // reset mCurretTargetContent to what it was
5805 mCurrentTargetContent = targetBeforeEvent;
5806
5807 // Now flush all pending notifications, for better responsiveness.
5808 FlushLayout(aPresContext);
5809}
5810
5811void EventStateManager::FireDragEnterOrExit(nsPresContext* aPresContext,
5812 WidgetDragEvent* aDragEvent,
5813 EventMessage aMessage,
5814 nsIContent* aRelatedTarget,
5815 nsIContent* aTargetContent,
5816 AutoWeakFrame& aTargetFrame) {
5817 MOZ_ASSERT(aMessage == eDragLeave || aMessage == eDragExit ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eDragLeave || aMessage == eDragExit || aMessage
== eDragEnter)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aMessage == eDragLeave || aMessage
== eDragExit || aMessage == eDragEnter))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eDragLeave || aMessage == eDragExit || aMessage == eDragEnter"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5818); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eDragLeave || aMessage == eDragExit || aMessage == eDragEnter"
")"); do { *((volatile int*)__null) = 5818; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5818 aMessage == eDragEnter)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eDragLeave || aMessage == eDragExit || aMessage
== eDragEnter)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aMessage == eDragLeave || aMessage
== eDragExit || aMessage == eDragEnter))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eDragLeave || aMessage == eDragExit || aMessage == eDragEnter"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5818); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eDragLeave || aMessage == eDragExit || aMessage == eDragEnter"
")"); do { *((volatile int*)__null) = 5818; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5819 nsEventStatus status = nsEventStatus_eIgnore;
5820 WidgetDragEvent event(aDragEvent->IsTrusted(), aMessage, aDragEvent->mWidget);
5821 event.AssignDragEventData(*aDragEvent, false);
5822 event.mFlags.mIsSynthesizedForTests =
5823 aDragEvent->mFlags.mIsSynthesizedForTests;
5824 event.mRelatedTarget = aRelatedTarget;
5825 if (aMessage == eDragExit && !StaticPrefs::dom_event_dragexit_enabled()) {
5826 event.mFlags.mOnlyChromeDispatch = true;
5827 }
5828
5829 mCurrentTargetContent = aTargetContent;
5830
5831 if (aTargetContent != aRelatedTarget) {
5832 // XXX This event should still go somewhere!!
5833 if (aTargetContent) {
5834 EventDispatcher::Dispatch(aTargetContent, aPresContext, &event, nullptr,
5835 &status);
5836 }
5837
5838 // adjust the drag hover if the dragenter event was cancelled or this is a
5839 // drag exit
5840 if (status == nsEventStatus_eConsumeNoDefault || aMessage == eDragExit) {
5841 SetContentState((aMessage == eDragEnter) ? aTargetContent : nullptr,
5842 ElementState::DRAGOVER);
5843 }
5844
5845 // collect any changes to moz cursor settings stored in the event's
5846 // data transfer.
5847 UpdateDragDataTransfer(&event);
5848 }
5849
5850 // Finally dispatch the event to the frame
5851 if (aTargetFrame) {
5852 aTargetFrame->HandleEvent(aPresContext, &event, &status);
5853 }
5854}
5855
5856void EventStateManager::UpdateDragDataTransfer(WidgetDragEvent* dragEvent) {
5857 NS_ASSERTION(dragEvent, "drag event is null in UpdateDragDataTransfer!")do { if (!(dragEvent)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "drag event is null in UpdateDragDataTransfer!"
, "dragEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5857); MOZ_PretendNoReturn(); } } while (0)
;
5858 if (!dragEvent->mDataTransfer) {
5859 return;
5860 }
5861
5862 nsCOMPtr<nsIDragSession> dragSession =
5863 nsContentUtils::GetDragSession(mPresContext);
5864
5865 if (dragSession) {
5866 // the initial dataTransfer is the one from the dragstart event that
5867 // was set on the dragSession when the drag began.
5868 RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer();
5869 if (initialDataTransfer) {
5870 // retrieve the current moz cursor setting and save it.
5871 nsAutoString mozCursor;
5872 dragEvent->mDataTransfer->GetMozCursor(mozCursor);
5873 initialDataTransfer->SetMozCursor(mozCursor);
5874 }
5875 }
5876}
5877
5878nsresult EventStateManager::SetClickCount(WidgetMouseEvent* aEvent,
5879 nsEventStatus* aStatus,
5880 nsIContent* aOverrideClickTarget) {
5881 nsCOMPtr<nsIContent> mouseContent = aOverrideClickTarget;
5882 if (!mouseContent && mCurrentTarget) {
5883 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(mouseContent));
5884 }
5885 if (mouseContent && mouseContent->IsText()) {
5886 nsINode* parent = mouseContent->GetFlattenedTreeParentNode();
5887 if (parent && parent->IsContent()) {
5888 mouseContent = parent->AsContent();
5889 }
5890 }
5891
5892 LastMouseDownInfo& mouseDownInfo = GetLastMouseDownInfo(aEvent->mButton);
5893 if (aEvent->mMessage == eMouseDown) {
5894 mouseDownInfo.mLastMouseDownContent =
5895 !aEvent->mClickEventPrevented ? mouseContent : nullptr;
5896
5897 if (mouseDownInfo.mLastMouseDownContent) {
5898 if (HTMLInputElement* input = HTMLInputElement::FromNodeOrNull(
5899 mouseDownInfo.mLastMouseDownContent)) {
5900 mouseDownInfo.mLastMouseDownInputControlType =
5901 Some(input->ControlType());
5902 } else if (mouseDownInfo.mLastMouseDownContent
5903 ->IsInNativeAnonymousSubtree()) {
5904 if (HTMLInputElement* input = HTMLInputElement::FromNodeOrNull(
5905 mouseDownInfo.mLastMouseDownContent
5906 ->GetFlattenedTreeParent())) {
5907 mouseDownInfo.mLastMouseDownInputControlType =
5908 Some(input->ControlType());
5909 }
5910 }
5911 }
5912 } else {
5913 aEvent->mClickTarget =
5914 !aEvent->mClickEventPrevented
5915 ? GetCommonAncestorForMouseUp(
5916 mouseContent, mouseDownInfo.mLastMouseDownContent,
5917 mouseDownInfo.mLastMouseDownInputControlType)
5918 : nullptr;
5919 if (aEvent->mClickTarget) {
5920 aEvent->mClickCount = mouseDownInfo.mClickCount;
5921 mouseDownInfo.mClickCount = 0;
5922 } else {
5923 aEvent->mClickCount = 0;
5924 }
5925 mouseDownInfo.mLastMouseDownContent = nullptr;
5926 mouseDownInfo.mLastMouseDownInputControlType = Nothing();
5927 }
5928
5929 return NS_OK;
5930}
5931
5932// static
5933bool EventStateManager::EventCausesClickEvents(
5934 const WidgetMouseEvent& aMouseEvent) {
5935 if (NS_WARN_IF(aMouseEvent.mMessage != eMouseUp)NS_warn_if_impl(aMouseEvent.mMessage != eMouseUp, "aMouseEvent.mMessage != eMouseUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5935)
) {
5936 return false;
5937 }
5938 // If the mouseup event is synthesized event, we don't need to dispatch
5939 // click events.
5940 if (!aMouseEvent.IsReal()) {
5941 return false;
5942 }
5943 // If mouse is still over same element, clickcount will be > 1.
5944 // If it has moved it will be zero, so no click.
5945 if (!aMouseEvent.mClickCount || !aMouseEvent.mClickTarget) {
5946 return false;
5947 }
5948 // If click event was explicitly prevented, we shouldn't dispatch it.
5949 if (aMouseEvent.mClickEventPrevented) {
5950 return false;
5951 }
5952 // Check that the window isn't disabled before firing a click
5953 // (see bug 366544).
5954 return !(aMouseEvent.mWidget && !aMouseEvent.mWidget->IsEnabled());
5955}
5956
5957nsresult EventStateManager::InitAndDispatchClickEvent(
5958 WidgetMouseEvent* aMouseUpEvent, nsEventStatus* aStatus,
5959 EventMessage aMessage, PresShell* aPresShell, nsIContent* aMouseUpContent,
5960 AutoWeakFrame aCurrentTarget, bool aNoContentDispatch,
5961 nsIContent* aOverrideClickTarget) {
5962 MOZ_ASSERT(aMouseUpEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseUpEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseUpEvent))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aMouseUpEvent",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5962); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpEvent"
")"); do { *((volatile int*)__null) = 5962; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5963 MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(EventCausesClickEvents(*aMouseUpEvent))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(EventCausesClickEvents(*aMouseUpEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("EventCausesClickEvents(*aMouseUpEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5963); AnnotateMozCrashReason("MOZ_ASSERT" "(" "EventCausesClickEvents(*aMouseUpEvent)"
")"); do { *((volatile int*)__null) = 5963; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5964 MOZ_ASSERT(aMouseUpContent || aCurrentTarget || aOverrideClickTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseUpContent || aCurrentTarget || aOverrideClickTarget
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aMouseUpContent || aCurrentTarget || aOverrideClickTarget
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aMouseUpContent || aCurrentTarget || aOverrideClickTarget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5964); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpContent || aCurrentTarget || aOverrideClickTarget"
")"); do { *((volatile int*)__null) = 5964; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5965
5966 Maybe<WidgetPointerEvent> pointerEvent;
5967 Maybe<WidgetMouseEvent> mouseEvent;
5968 if (IsPointerEventMessage(aMessage)) {
5969 pointerEvent.emplace(aMouseUpEvent->IsTrusted(), aMessage,
5970 aMouseUpEvent->mWidget);
5971 } else {
5972 mouseEvent.emplace(aMouseUpEvent->IsTrusted(), aMessage,
5973 aMouseUpEvent->mWidget, WidgetMouseEvent::eReal);
5974 }
5975
5976 WidgetMouseEvent& mouseOrPointerEvent =
5977 pointerEvent.isSome() ? pointerEvent.ref() : mouseEvent.ref();
5978
5979 mouseOrPointerEvent.mRefPoint = aMouseUpEvent->mRefPoint;
5980 mouseOrPointerEvent.mClickCount = aMouseUpEvent->mClickCount;
5981 mouseOrPointerEvent.mModifiers = aMouseUpEvent->mModifiers;
5982 mouseOrPointerEvent.mButtons = aMouseUpEvent->mButtons;
5983 mouseOrPointerEvent.mTimeStamp = aMouseUpEvent->mTimeStamp;
5984 mouseOrPointerEvent.mFlags.mOnlyChromeDispatch = aNoContentDispatch;
5985 mouseOrPointerEvent.mFlags.mNoContentDispatch = aNoContentDispatch;
5986 mouseOrPointerEvent.mButton = aMouseUpEvent->mButton;
5987 mouseOrPointerEvent.pointerId = aMouseUpEvent->pointerId;
5988 mouseOrPointerEvent.mInputSource = aMouseUpEvent->mInputSource;
5989 nsIContent* target = aMouseUpContent;
5990 nsIFrame* targetFrame = aCurrentTarget;
5991 if (aOverrideClickTarget) {
5992 target = aOverrideClickTarget;
5993 targetFrame = aOverrideClickTarget->GetPrimaryFrame();
5994 }
5995
5996 if (!target->IsInComposedDoc()) {
5997 return NS_OK;
5998 }
5999
6000 // Use local event status for each click event dispatching since it'll be
6001 // cleared by EventStateManager::PreHandleEvent(). Therefore, dispatching
6002 // an event means that previous event status will be ignored.
6003 nsEventStatus status = nsEventStatus_eIgnore;
6004 nsresult rv = aPresShell->HandleEventWithTarget(
6005 &mouseOrPointerEvent, targetFrame, MOZ_KnownLive(target)(target), &status);
6006
6007 // Copy mMultipleActionsPrevented flag from a click event to the mouseup
6008 // event only when it's set to true. It may be set to true if an editor has
6009 // already handled it. This is important to avoid two or more default
6010 // actions handled here.
6011 aMouseUpEvent->mFlags.mMultipleActionsPrevented |=
6012 mouseOrPointerEvent.mFlags.mMultipleActionsPrevented;
6013 // If current status is nsEventStatus_eConsumeNoDefault, we don't need to
6014 // overwrite it.
6015 if (*aStatus == nsEventStatus_eConsumeNoDefault) {
6016 return rv;
6017 }
6018 // If new status is nsEventStatus_eConsumeNoDefault or
6019 // nsEventStatus_eConsumeDoDefault, use it.
6020 if (status == nsEventStatus_eConsumeNoDefault ||
6021 status == nsEventStatus_eConsumeDoDefault) {
6022 *aStatus = status;
6023 return rv;
6024 }
6025 // Otherwise, keep the original status.
6026 return rv;
6027}
6028
6029nsresult EventStateManager::PostHandleMouseUp(
6030 WidgetMouseEvent* aMouseUpEvent, nsEventStatus* aStatus,
6031 nsIContent* aOverrideClickTarget) {
6032 MOZ_ASSERT(aMouseUpEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseUpEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseUpEvent))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aMouseUpEvent",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6032); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpEvent"
")"); do { *((volatile int*)__null) = 6032; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6033 MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(EventCausesClickEvents(*aMouseUpEvent))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(EventCausesClickEvents(*aMouseUpEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("EventCausesClickEvents(*aMouseUpEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6033); AnnotateMozCrashReason("MOZ_ASSERT" "(" "EventCausesClickEvents(*aMouseUpEvent)"
")"); do { *((volatile int*)__null) = 6033; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6034 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6034); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 6034; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6035
6036 RefPtr<PresShell> presShell = mPresContext->GetPresShell();
6037 if (!presShell) {
6038 return NS_OK;
6039 }
6040
6041 nsCOMPtr<nsIContent> clickTarget =
6042 nsIContent::FromEventTargetOrNull(aMouseUpEvent->mClickTarget);
6043 NS_ENSURE_STATE(clickTarget)do { if ((__builtin_expect(!!(!(clickTarget)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "clickTarget" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6043); return NS_ERROR_UNEXPECTED; } } while (false)
;
6044
6045 // Fire click events if the event target is still available.
6046 // Note that do not include the eMouseUp event's status since we ignore it
6047 // for compatibility with the other browsers.
6048 nsEventStatus status = nsEventStatus_eIgnore;
6049 nsresult rv = DispatchClickEvents(presShell, aMouseUpEvent, &status,
6050 clickTarget, aOverrideClickTarget);
6051 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6051)
) {
6052 return rv;
6053 }
6054
6055 // Do not do anything if preceding click events are consumed.
6056 // Note that Chromium dispatches "paste" event and actually pates clipboard
6057 // text into focused editor even if the preceding click events are consumed.
6058 // However, this is different from our traditional behavior and does not
6059 // conform to DOM events. If we need to keep compatibility with Chromium,
6060 // we should change it later.
6061 if (status == nsEventStatus_eConsumeNoDefault) {
6062 *aStatus = nsEventStatus_eConsumeNoDefault;
6063 return NS_OK;
6064 }
6065
6066 // Handle middle click paste if it's enabled and the mouse button is middle.
6067 if (aMouseUpEvent->mButton != MouseButton::eMiddle ||
6068 !WidgetMouseEvent::IsMiddleClickPasteEnabled()) {
6069 return NS_OK;
6070 }
6071 DebugOnly<nsresult> rvIgnored =
6072 HandleMiddleClickPaste(presShell, aMouseUpEvent, &status, nullptr);
6073 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to paste for a middle click"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6074); } } while (false)
6074 "Failed to paste for a middle click")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to paste for a middle click"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6074); } } while (false)
;
6075
6076 // If new status is nsEventStatus_eConsumeNoDefault or
6077 // nsEventStatus_eConsumeDoDefault, use it.
6078 if (*aStatus != nsEventStatus_eConsumeNoDefault &&
6079 (status == nsEventStatus_eConsumeNoDefault ||
6080 status == nsEventStatus_eConsumeDoDefault)) {
6081 *aStatus = status;
6082 }
6083
6084 // Don't return error even if middle mouse paste fails since we haven't
6085 // handled it here.
6086 return NS_OK;
6087}
6088
6089nsresult EventStateManager::DispatchClickEvents(
6090 PresShell* aPresShell, WidgetMouseEvent* aMouseUpEvent,
6091 nsEventStatus* aStatus, nsIContent* aClickTarget,
6092 nsIContent* aOverrideClickTarget) {
6093 MOZ_ASSERT(aPresShell)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresShell)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresShell))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aPresShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6093); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresShell"
")"); do { *((volatile int*)__null) = 6093; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6094 MOZ_ASSERT(aMouseUpEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseUpEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseUpEvent))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aMouseUpEvent",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6094); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpEvent"
")"); do { *((volatile int*)__null) = 6094; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6095 MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(EventCausesClickEvents(*aMouseUpEvent))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(EventCausesClickEvents(*aMouseUpEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("EventCausesClickEvents(*aMouseUpEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6095); AnnotateMozCrashReason("MOZ_ASSERT" "(" "EventCausesClickEvents(*aMouseUpEvent)"
")"); do { *((volatile int*)__null) = 6095; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6096 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6096); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 6096; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6097 MOZ_ASSERT(aClickTarget || aOverrideClickTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aClickTarget || aOverrideClickTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aClickTarget || aOverrideClickTarget
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aClickTarget || aOverrideClickTarget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6097); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aClickTarget || aOverrideClickTarget"
")"); do { *((volatile int*)__null) = 6097; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6098
6099 bool notDispatchToContents =
6100 (aMouseUpEvent->mButton == MouseButton::eMiddle ||
6101 aMouseUpEvent->mButton == MouseButton::eSecondary);
6102
6103 bool fireAuxClick = notDispatchToContents;
6104
6105 AutoWeakFrame currentTarget = aClickTarget->GetPrimaryFrame();
6106 nsresult rv = InitAndDispatchClickEvent(
6107 aMouseUpEvent, aStatus, ePointerClick, aPresShell, aClickTarget,
6108 currentTarget, notDispatchToContents, aOverrideClickTarget);
6109 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6109)
) {
6110 return rv;
6111 }
6112
6113 // Fire auxclick event if necessary.
6114 if (fireAuxClick && *aStatus != nsEventStatus_eConsumeNoDefault &&
6115 aClickTarget && aClickTarget->IsInComposedDoc()) {
6116 rv = InitAndDispatchClickEvent(aMouseUpEvent, aStatus, ePointerAuxClick,
6117 aPresShell, aClickTarget, currentTarget,
6118 false, aOverrideClickTarget);
6119 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to dispatch ePointerAuxClick"
, "NS_SUCCEEDED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6120); } } while (false)
6120 "Failed to dispatch ePointerAuxClick")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to dispatch ePointerAuxClick"
, "NS_SUCCEEDED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6120); } } while (false)
;
6121 }
6122
6123 // Fire double click event if click count is 2.
6124 if (aMouseUpEvent->mClickCount == 2 && !fireAuxClick && aClickTarget &&
6125 aClickTarget->IsInComposedDoc()) {
6126 rv = InitAndDispatchClickEvent(aMouseUpEvent, aStatus, eMouseDoubleClick,
6127 aPresShell, aClickTarget, currentTarget,
6128 notDispatchToContents, aOverrideClickTarget);
6129 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6129)
) {
6130 return rv;
6131 }
6132 }
6133
6134 return rv;
6135}
6136
6137nsresult EventStateManager::HandleMiddleClickPaste(
6138 PresShell* aPresShell, WidgetMouseEvent* aMouseEvent,
6139 nsEventStatus* aStatus, EditorBase* aEditorBase) {
6140 MOZ_ASSERT(aPresShell)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresShell)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresShell))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aPresShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6140); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresShell"
")"); do { *((volatile int*)__null) = 6140; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6141 MOZ_ASSERT(aMouseEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseEvent))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aMouseEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6141); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseEvent"
")"); do { *((volatile int*)__null) = 6141; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6142 MOZ_ASSERT((aMouseEvent->mMessage == ePointerAuxClick &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aMouseEvent->mMessage == ePointerAuxClick &&
aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents
(*aMouseEvent))>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!((aMouseEvent->mMessage == ePointerAuxClick
&& aMouseEvent->mButton == MouseButton::eMiddle) ||
EventCausesClickEvents(*aMouseEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6144); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
")"); do { *((volatile int*)__null) = 6144; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6143 aMouseEvent->mButton == MouseButton::eMiddle) ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aMouseEvent->mMessage == ePointerAuxClick &&
aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents
(*aMouseEvent))>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!((aMouseEvent->mMessage == ePointerAuxClick
&& aMouseEvent->mButton == MouseButton::eMiddle) ||
EventCausesClickEvents(*aMouseEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6144); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
")"); do { *((volatile int*)__null) = 6144; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6144 EventCausesClickEvents(*aMouseEvent))do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aMouseEvent->mMessage == ePointerAuxClick &&
aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents
(*aMouseEvent))>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!((aMouseEvent->mMessage == ePointerAuxClick
&& aMouseEvent->mButton == MouseButton::eMiddle) ||
EventCausesClickEvents(*aMouseEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6144); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
")"); do { *((volatile int*)__null) = 6144; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6145 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6145); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 6145; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6146 MOZ_ASSERT(*aStatus != nsEventStatus_eConsumeNoDefault)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(*aStatus != nsEventStatus_eConsumeNoDefault))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6146); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault"
")"); do { *((volatile int*)__null) = 6146; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6147
6148 // Even if we're called twice or more for a mouse operation, we should
6149 // handle only once. Although mMultipleActionsPrevented may be set to
6150 // true by different event handler in the future, we can use it for now.
6151 if (aMouseEvent->mFlags.mMultipleActionsPrevented) {
6152 return NS_OK;
6153 }
6154 aMouseEvent->mFlags.mMultipleActionsPrevented = true;
6155
6156 RefPtr<Selection> selection;
6157 if (aEditorBase) {
6158 selection = aEditorBase->GetSelection();
6159 if (NS_WARN_IF(!selection)NS_warn_if_impl(!selection, "!selection", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6159)
) {
6160 return NS_ERROR_FAILURE;
6161 }
6162 } else {
6163 Document* document = aPresShell->GetDocument();
6164 if (NS_WARN_IF(!document)NS_warn_if_impl(!document, "!document", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6164)
) {
6165 return NS_ERROR_FAILURE;
6166 }
6167 selection = nsCopySupport::GetSelectionForCopy(document);
6168 if (NS_WARN_IF(!selection)NS_warn_if_impl(!selection, "!selection", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6168)
) {
6169 return NS_ERROR_FAILURE;
6170 }
6171
6172 const nsRange* range = selection->GetRangeAt(0);
6173 if (range) {
6174 nsINode* target = range->GetStartContainer();
6175 if (target && target->OwnerDoc()->IsInChromeDocShell()) {
6176 // In Chrome document, limit middle-click pasting to only the editor
6177 // because it looks odd if pasting works in the focused editor when you
6178 // middle-click toolbar or something which are far from the editor.
6179 // However, as DevTools especially Web Console module assumes that paste
6180 // event will be fired when middle-click even on not editor, don't limit
6181 // it.
6182 return NS_OK;
6183 }
6184 }
6185 }
6186
6187 // Don't modify selection here because we've already set caret to the point
6188 // at "mousedown" event.
6189
6190 nsIClipboard::ClipboardType clipboardType = nsIClipboard::kGlobalClipboard;
6191 nsCOMPtr<nsIClipboard> clipboardService =
6192 do_GetService("@mozilla.org/widget/clipboard;1");
6193 if (clipboardService && clipboardService->IsClipboardTypeSupported(
6194 nsIClipboard::kSelectionClipboard)) {
6195 clipboardType = nsIClipboard::kSelectionClipboard;
6196 }
6197
6198 // Fire ePaste event by ourselves since we need to dispatch "paste" event
6199 // even if the middle click event was consumed for compatibility with
6200 // Chromium.
6201 if (!nsCopySupport::FireClipboardEvent(ePaste, Some(clipboardType),
6202 aPresShell, selection)) {
6203 *aStatus = nsEventStatus_eConsumeNoDefault;
6204 return NS_OK;
6205 }
6206
6207 // Although we've fired "paste" event, there is no editor to accept the
6208 // clipboard content.
6209 if (!aEditorBase) {
6210 return NS_OK;
6211 }
6212
6213 // Check if the editor is still the good target to paste.
6214 if (aEditorBase->Destroyed() || aEditorBase->IsReadonly()) {
6215 // XXX Should we consume the event when the editor is readonly and/or
6216 // disabled?
6217 return NS_OK;
6218 }
6219
6220 // The selection may have been modified during reflow. Therefore, we
6221 // should adjust event target to pass IsAcceptableInputEvent().
6222 const nsRange* range = selection->GetRangeAt(0);
6223 if (!range) {
6224 return NS_OK;
6225 }
6226 WidgetMouseEvent mouseEvent(*aMouseEvent);
6227 mouseEvent.mOriginalTarget = range->GetStartContainer();
6228 if (NS_WARN_IF(!mouseEvent.mOriginalTarget)NS_warn_if_impl(!mouseEvent.mOriginalTarget, "!mouseEvent.mOriginalTarget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6228)
||
6229 !aEditorBase->IsAcceptableInputEvent(&mouseEvent)) {
6230 return NS_OK;
6231 }
6232
6233 // If Control key is pressed, we should paste clipboard content as
6234 // quotation. Otherwise, paste it as is.
6235 if (aMouseEvent->IsControl()) {
6236 DebugOnly<nsresult> rv = aEditorBase->PasteAsQuotationAsAction(
6237 clipboardType, EditorBase::DispatchPasteEvent::No);
6238 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to paste as quotation")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to paste as quotation"
, "NS_SUCCEEDED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6238); } } while (false)
;
6239 } else {
6240 DebugOnly<nsresult> rv = aEditorBase->PasteAsAction(
6241 clipboardType, EditorBase::DispatchPasteEvent::No);
6242 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to paste")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to paste", "NS_SUCCEEDED(rv)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6242); } } while (false)
;
6243 }
6244 *aStatus = nsEventStatus_eConsumeNoDefault;
6245
6246 return NS_OK;
6247}
6248
6249void EventStateManager::ConsumeInteractionData(
6250 Record<nsString, dom::InteractionData>& aInteractions) {
6251 OnTypingInteractionEnded();
6252
6253 aInteractions.Entries().Clear();
6254 auto newEntry = aInteractions.Entries().AppendElement();
6255 newEntry->mKey = u"Typing"_ns;
6256 newEntry->mValue = gTypingInteraction;
6257 gTypingInteraction = {};
6258}
6259
6260nsIFrame* EventStateManager::GetEventTarget() {
6261 PresShell* presShell;
6262 if (mCurrentTarget || !mPresContext ||
6263 !(presShell = mPresContext->GetPresShell())) {
6264 return mCurrentTarget;
6265 }
6266
6267 if (mCurrentTargetContent) {
6268 mCurrentTarget = mPresContext->GetPrimaryFrameFor(mCurrentTargetContent);
6269 if (mCurrentTarget) {
6270 return mCurrentTarget;
6271 }
6272 }
6273
6274 nsIFrame* frame = presShell->GetCurrentEventFrame();
6275 return (mCurrentTarget = frame);
6276}
6277
6278already_AddRefed<nsIContent> EventStateManager::GetEventTargetContent(
6279 WidgetEvent* aEvent) {
6280 if (aEvent && (aEvent->mMessage == eFocus || aEvent->mMessage == eBlur)) {
6281 nsCOMPtr<nsIContent> content = GetFocusedElement();
6282 return content.forget();
6283 }
6284
6285 if (mCurrentTargetContent) {
6286 nsCOMPtr<nsIContent> content = mCurrentTargetContent;
6287 return content.forget();
6288 }
6289
6290 nsCOMPtr<nsIContent> content;
6291 if (PresShell* presShell = mPresContext->GetPresShell()) {
6292 content = presShell->GetEventTargetContent(aEvent);
6293 }
6294
6295 // Some events here may set mCurrentTarget but not set the corresponding
6296 // event target in the PresShell.
6297 if (!content && mCurrentTarget) {
6298 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(content));
6299 }
6300
6301 return content.forget();
6302}
6303
6304static Element* GetLabelTarget(nsIContent* aPossibleLabel) {
6305 mozilla::dom::HTMLLabelElement* label =
6306 mozilla::dom::HTMLLabelElement::FromNode(aPossibleLabel);
6307 if (!label) return nullptr;
6308
6309 return label->GetLabeledElement();
6310}
6311
6312/* static */
6313inline void EventStateManager::DoStateChange(Element* aElement,
6314 ElementState aState,
6315 bool aAddState) {
6316 if (aAddState) {
6317 aElement->AddStates(aState);
6318 } else {
6319 aElement->RemoveStates(aState);
6320 }
6321}
6322
6323/* static */
6324inline void EventStateManager::DoStateChange(nsIContent* aContent,
6325 ElementState aState,
6326 bool aStateAdded) {
6327 if (aContent->IsElement()) {
6328 DoStateChange(aContent->AsElement(), aState, aStateAdded);
6329 }
6330}
6331
6332/* static */
6333void EventStateManager::UpdateAncestorState(nsIContent* aStartNode,
6334 nsIContent* aStopBefore,
6335 ElementState aState,
6336 bool aAddState) {
6337 for (; aStartNode && aStartNode != aStopBefore;
6338 aStartNode = aStartNode->GetFlattenedTreeParent()) {
6339 // We might be starting with a non-element (e.g. a text node) and
6340 // if someone is doing something weird might be ending with a
6341 // non-element too (e.g. a document fragment)
6342 if (!aStartNode->IsElement()) {
6343 continue;
6344 }
6345 Element* element = aStartNode->AsElement();
6346 DoStateChange(element, aState, aAddState);
6347 Element* labelTarget = GetLabelTarget(element);
6348 if (labelTarget) {
6349 DoStateChange(labelTarget, aState, aAddState);
6350 }
6351 }
6352
6353 if (aAddState) {
6354 // We might be in a situation where a node was in hover both
6355 // because it was hovered and because the label for it was
6356 // hovered, and while we stopped hovering the node the label is
6357 // still hovered. Or we might have had two nested labels for the
6358 // same node, and while one is no longer hovered the other still
6359 // is. In that situation, the label that's still hovered will be
6360 // aStopBefore or some ancestor of it, and the call we just made
6361 // to UpdateAncestorState with aAddState = false would have
6362 // removed the hover state from the node. But the node should
6363 // still be in hover state. To handle this situation we need to
6364 // keep walking up the tree and any time we find a label mark its
6365 // corresponding node as still in our state.
6366 for (; aStartNode; aStartNode = aStartNode->GetFlattenedTreeParent()) {
6367 if (!aStartNode->IsElement()) {
6368 continue;
6369 }
6370
6371 Element* labelTarget = GetLabelTarget(aStartNode->AsElement());
6372 if (labelTarget && !labelTarget->State().HasState(aState)) {
6373 DoStateChange(labelTarget, aState, true);
6374 }
6375 }
6376 }
6377}
6378
6379// static
6380bool CanContentHaveActiveState(nsIContent& aContent) {
6381 // Editable content can never become active since their default actions
6382 // are disabled. Watch out for editable content in native anonymous
6383 // subtrees though, as they belong to text controls.
6384 return !aContent.IsEditable() || aContent.IsInNativeAnonymousSubtree();
6385}
6386
6387bool EventStateManager::SetContentState(nsIContent* aContent,
6388 ElementState aState) {
6389 MOZ_ASSERT(ManagesState(aState), "Unexpected state")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ManagesState(aState))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ManagesState(aState)))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("ManagesState(aState)"
" (" "Unexpected state" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6389); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ManagesState(aState)"
") (" "Unexpected state" ")"); do { *((volatile int*)__null)
= 6389; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
6390
6391 nsCOMPtr<nsIContent> notifyContent1;
6392 nsCOMPtr<nsIContent> notifyContent2;
6393 bool updateAncestors;
6394
6395 if (aState == ElementState::HOVER || aState == ElementState::ACTIVE) {
6396 // Hover and active are hierarchical
6397 updateAncestors = true;
6398
6399 // check to see that this state is allowed by style. Check dragover too?
6400 // XXX Is this even what we want?
6401 if (mCurrentTarget &&
6402 mCurrentTarget->StyleUI()->UserInput() == StyleUserInput::None) {
6403 return false;
6404 }
6405
6406 if (aState == ElementState::ACTIVE) {
6407 if (aContent && !CanContentHaveActiveState(*aContent)) {
6408 aContent = nullptr;
6409 }
6410 if (aContent != mActiveContent) {
6411 notifyContent1 = aContent;
6412 notifyContent2 = mActiveContent;
6413 mActiveContent = aContent;
6414 }
6415 } else {
6416 NS_ASSERTION(aState == ElementState::HOVER, "How did that happen?")do { if (!(aState == ElementState::HOVER)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "How did that happen?", "aState == ElementState::HOVER", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6416); MOZ_PretendNoReturn(); } } while (0)
;
6417 nsIContent* newHover;
6418
6419 if (mPresContext->IsDynamic()) {
6420 newHover = aContent;
6421 } else {
6422 NS_ASSERTION(!aContent || aContent->GetComposedDoc() ==do { if (!(!aContent || aContent->GetComposedDoc() == mPresContext
->PresShell()->GetDocument())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected document", "!aContent || aContent->GetComposedDoc() == mPresContext->PresShell()->GetDocument()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6424); MOZ_PretendNoReturn(); } } while (0)
6423 mPresContext->PresShell()->GetDocument(),do { if (!(!aContent || aContent->GetComposedDoc() == mPresContext
->PresShell()->GetDocument())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected document", "!aContent || aContent->GetComposedDoc() == mPresContext->PresShell()->GetDocument()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6424); MOZ_PretendNoReturn(); } } while (0)
6424 "Unexpected document")do { if (!(!aContent || aContent->GetComposedDoc() == mPresContext
->PresShell()->GetDocument())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected document", "!aContent || aContent->GetComposedDoc() == mPresContext->PresShell()->GetDocument()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6424); MOZ_PretendNoReturn(); } } while (0)
;
6425 nsIFrame* frame = aContent ? aContent->GetPrimaryFrame() : nullptr;
6426 if (frame && nsLayoutUtils::IsViewportScrollbarFrame(frame)) {
6427 // The scrollbars of viewport should not ignore the hover state.
6428 // Because they are *not* the content of the web page.
6429 newHover = aContent;
6430 } else {
6431 // All contents of the web page should ignore the hover state.
6432 newHover = nullptr;
6433 }
6434 }
6435
6436 if (newHover != mHoverContent) {
6437 notifyContent1 = newHover;
6438 notifyContent2 = mHoverContent;
6439 mHoverContent = newHover;
6440 }
6441 }
6442 } else {
6443 updateAncestors = false;
6444 if (aState == ElementState::DRAGOVER) {
6445 if (aContent != sDragOverContent) {
6446 notifyContent1 = aContent;
6447 notifyContent2 = sDragOverContent;
6448 sDragOverContent = aContent;
6449 }
6450 } else if (aState == ElementState::URLTARGET) {
6451 if (aContent != mURLTargetContent) {
6452 notifyContent1 = aContent;
6453 notifyContent2 = mURLTargetContent;
6454 mURLTargetContent = aContent;
6455 }
6456 }
6457 }
6458
6459 // We need to keep track of which of notifyContent1 and notifyContent2 is
6460 // getting the state set and which is getting it unset. If both are
6461 // non-null, then notifyContent1 is having the state set and notifyContent2
6462 // is having it unset. But if one of them is null, we need to keep track of
6463 // the right thing for notifyContent1 explicitly.
6464 bool content1StateSet = true;
6465 if (!notifyContent1) {
6466 // This is ok because FindCommonAncestor wouldn't find anything
6467 // anyway if notifyContent1 is null.
6468 notifyContent1 = notifyContent2;
6469 notifyContent2 = nullptr;
6470 content1StateSet = false;
6471 }
6472
6473 if (notifyContent1 && mPresContext) {
6474 EnsureDocument(mPresContext);
6475 if (mDocument) {
6476 nsAutoScriptBlocker scriptBlocker;
6477
6478 if (updateAncestors) {
6479 nsCOMPtr<nsIContent> commonAncestor =
6480 FindCommonAncestor(notifyContent1, notifyContent2);
6481 if (notifyContent2) {
6482 // It's very important to first notify the state removal and
6483 // then the state addition, because due to labels it's
6484 // possible that we're removing state from some element but
6485 // then adding it again (say because mHoverContent changed
6486 // from a control to its label).
6487 UpdateAncestorState(notifyContent2, commonAncestor, aState, false);
6488 }
6489 UpdateAncestorState(notifyContent1, commonAncestor, aState,
6490 content1StateSet);
6491 } else {
6492 if (notifyContent2) {
6493 DoStateChange(notifyContent2, aState, false);
6494 }
6495 DoStateChange(notifyContent1, aState, content1StateSet);
6496 }
6497 }
6498 }
6499
6500 return true;
6501}
6502
6503void EventStateManager::RemoveNodeFromChainIfNeeded(ElementState aState,
6504 nsIContent* aContentRemoved,
6505 bool aNotify) {
6506 MOZ_ASSERT(aState == ElementState::HOVER || aState == ElementState::ACTIVE)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aState == ElementState::HOVER || aState == ElementState
::ACTIVE)>::isValid, "invalid assertion condition"); if ((
__builtin_expect(!!(!(!!(aState == ElementState::HOVER || aState
== ElementState::ACTIVE))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aState == ElementState::HOVER || aState == ElementState::ACTIVE"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6506); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aState == ElementState::HOVER || aState == ElementState::ACTIVE"
")"); do { *((volatile int*)__null) = 6506; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6507 if (!aContentRemoved->IsElement() ||
6508 !aContentRemoved->AsElement()->State().HasState(aState)) {
6509 return;
6510 }
6511
6512 nsCOMPtr<nsIContent>& leaf =
6513 aState == ElementState::HOVER ? mHoverContent : mActiveContent;
6514
6515 MOZ_ASSERT(leaf)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(leaf)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(leaf))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("leaf", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6515); AnnotateMozCrashReason("MOZ_ASSERT" "(" "leaf" ")");
do { *((volatile int*)__null) = 6515; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6516 // These two NS_ASSERTIONS below can fail for Shadow DOM sometimes, and it's
6517 // not clear how to best handle it, see
6518 // https://github.com/whatwg/html/issues/4795 and bug 1551621.
6519 NS_ASSERTION(do { if (!(nsContentUtils::ContentIsFlattenedTreeDescendantOf
(leaf, aContentRemoved))) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"Flat tree and active / hover chain got out of sync", "nsContentUtils::ContentIsFlattenedTreeDescendantOf(leaf, aContentRemoved)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6521); MOZ_PretendNoReturn(); } } while (0)
6520 nsContentUtils::ContentIsFlattenedTreeDescendantOf(leaf, aContentRemoved),do { if (!(nsContentUtils::ContentIsFlattenedTreeDescendantOf
(leaf, aContentRemoved))) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"Flat tree and active / hover chain got out of sync", "nsContentUtils::ContentIsFlattenedTreeDescendantOf(leaf, aContentRemoved)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6521); MOZ_PretendNoReturn(); } } while (0)
6521 "Flat tree and active / hover chain got out of sync")do { if (!(nsContentUtils::ContentIsFlattenedTreeDescendantOf
(leaf, aContentRemoved))) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"Flat tree and active / hover chain got out of sync", "nsContentUtils::ContentIsFlattenedTreeDescendantOf(leaf, aContentRemoved)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6521); MOZ_PretendNoReturn(); } } while (0)
;
6522
6523 nsIContent* newLeaf = aContentRemoved->GetFlattenedTreeParent();
6524 MOZ_ASSERT(!newLeaf || newLeaf->IsElement())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!newLeaf || newLeaf->IsElement())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!newLeaf || newLeaf->IsElement
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!newLeaf || newLeaf->IsElement()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6524); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!newLeaf || newLeaf->IsElement()"
")"); do { *((volatile int*)__null) = 6524; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6525 NS_ASSERTION(!newLeaf || newLeaf->AsElement()->State().HasState(aState),do { if (!(!newLeaf || newLeaf->AsElement()->State().HasState
(aState))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "State got out of sync because of shadow DOM"
, "!newLeaf || newLeaf->AsElement()->State().HasState(aState)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6526); MOZ_PretendNoReturn(); } } while (0)
6526 "State got out of sync because of shadow DOM")do { if (!(!newLeaf || newLeaf->AsElement()->State().HasState
(aState))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "State got out of sync because of shadow DOM"
, "!newLeaf || newLeaf->AsElement()->State().HasState(aState)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6526); MOZ_PretendNoReturn(); } } while (0)
;
6527 if (aNotify) {
6528 SetContentState(newLeaf, aState);
6529 } else {
6530 // We don't update the removed content's state here, since removing NAC
6531 // happens from layout and we don't really want to notify at that point or
6532 // what not.
6533 //
6534 // Also, NAC is not observable and NAC being removed will go away soon.
6535 leaf = newLeaf;
6536 }
6537 MOZ_ASSERT(leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(leaf == newLeaf || (aState == ElementState::ACTIVE &&
!leaf && !CanContentHaveActiveState(*newLeaf)))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(leaf == newLeaf || (aState == ElementState::ACTIVE &&
!leaf && !CanContentHaveActiveState(*newLeaf))))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf && !CanContentHaveActiveState(*newLeaf))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6538); AnnotateMozCrashReason("MOZ_ASSERT" "(" "leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf && !CanContentHaveActiveState(*newLeaf))"
")"); do { *((volatile int*)__null) = 6538; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6538 !CanContentHaveActiveState(*newLeaf)))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(leaf == newLeaf || (aState == ElementState::ACTIVE &&
!leaf && !CanContentHaveActiveState(*newLeaf)))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(leaf == newLeaf || (aState == ElementState::ACTIVE &&
!leaf && !CanContentHaveActiveState(*newLeaf))))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf && !CanContentHaveActiveState(*newLeaf))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6538); AnnotateMozCrashReason("MOZ_ASSERT" "(" "leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf && !CanContentHaveActiveState(*newLeaf))"
")"); do { *((volatile int*)__null) = 6538; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6539}
6540
6541void EventStateManager::NativeAnonymousContentRemoved(nsIContent* aContent) {
6542 MOZ_ASSERT(aContent->IsRootOfNativeAnonymousSubtree())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContent->IsRootOfNativeAnonymousSubtree())>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aContent->IsRootOfNativeAnonymousSubtree()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aContent->IsRootOfNativeAnonymousSubtree()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6542); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsRootOfNativeAnonymousSubtree()"
")"); do { *((volatile int*)__null) = 6542; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6543 RemoveNodeFromChainIfNeeded(ElementState::HOVER, aContent, false);
6544 RemoveNodeFromChainIfNeeded(ElementState::ACTIVE, aContent, false);
6545
6546 nsCOMPtr<nsIContent>& lastLeftMouseDownContent =
6547 mLastLeftMouseDownInfo.mLastMouseDownContent;
6548 if (lastLeftMouseDownContent &&
6549 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
6550 lastLeftMouseDownContent, aContent)) {
6551 lastLeftMouseDownContent = aContent->GetFlattenedTreeParent();
6552 }
6553
6554 nsCOMPtr<nsIContent>& lastMiddleMouseDownContent =
6555 mLastMiddleMouseDownInfo.mLastMouseDownContent;
6556 if (lastMiddleMouseDownContent &&
6557 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
6558 lastMiddleMouseDownContent, aContent)) {
6559 lastMiddleMouseDownContent = aContent->GetFlattenedTreeParent();
6560 }
6561
6562 nsCOMPtr<nsIContent>& lastRightMouseDownContent =
6563 mLastRightMouseDownInfo.mLastMouseDownContent;
6564 if (lastRightMouseDownContent &&
6565 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
6566 lastRightMouseDownContent, aContent)) {
6567 lastRightMouseDownContent = aContent->GetFlattenedTreeParent();
6568 }
6569}
6570
6571void EventStateManager::ContentRemoved(Document* aDocument,
6572 nsIContent* aContent) {
6573 /*
6574 * Anchor and area elements when focused or hovered might make the UI to show
6575 * the current link. We want to make sure that the UI gets informed when they
6576 * are actually removed from the DOM.
6577 */
6578 if (aContent->IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area) &&
6579 (aContent->AsElement()->State().HasAtLeastOneOfStates(
6580 ElementState::FOCUS | ElementState::HOVER))) {
6581 Element* element = aContent->AsElement();
6582 element->LeaveLink(element->GetPresContext(Element::eForComposedDoc));
6583 }
6584
6585 if (aContent->IsElement()) {
6586 if (RefPtr<nsPresContext> presContext = mPresContext) {
6587 IMEStateManager::OnRemoveContent(*presContext,
6588 MOZ_KnownLive(*aContent->AsElement())(*aContent->AsElement()));
6589 }
6590 WheelTransaction::OnRemoveElement(aContent);
6591 }
6592
6593 // inform the focus manager that the content is being removed. If this
6594 // content is focused, the focus will be removed without firing events.
6595 if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
6596 fm->ContentRemoved(aDocument, aContent);
6597 }
6598
6599 RemoveNodeFromChainIfNeeded(ElementState::HOVER, aContent, true);
6600 RemoveNodeFromChainIfNeeded(ElementState::ACTIVE, aContent, true);
6601
6602 if (sDragOverContent &&
6603 sDragOverContent->OwnerDoc() == aContent->OwnerDoc() &&
6604 nsContentUtils::ContentIsFlattenedTreeDescendantOf(sDragOverContent,
6605 aContent)) {
6606 sDragOverContent = nullptr;
6607 }
6608
6609 PointerEventHandler::ReleaseIfCaptureByDescendant(aContent);
6610
6611 if (mMouseEnterLeaveHelper) {
6612 const bool hadMouseOutTarget =
6613 mMouseEnterLeaveHelper->GetOutEventTarget() != nullptr;
6614 mMouseEnterLeaveHelper->ContentRemoved(*aContent);
6615 // If we lose the mouseout target, we need to dispatch mouseover on an
6616 // ancestor. For ensuring the chance to do it before next user input, we
6617 // need a synthetic mouse move.
6618 if (hadMouseOutTarget && !mMouseEnterLeaveHelper->GetOutEventTarget()) {
6619 if (PresShell* presShell =
6620 mPresContext ? mPresContext->GetPresShell() : nullptr) {
6621 presShell->SynthesizeMouseMove(false);
6622 }
6623 }
6624 }
6625 for (const auto& entry : mPointersEnterLeaveHelper) {
6626 if (entry.GetData()) {
6627 entry.GetData()->ContentRemoved(*aContent);
6628 }
6629 }
6630}
6631
6632void EventStateManager::TextControlRootWillBeRemoved(
6633 TextControlElement& aTextControlElement) {
6634 if (!mGestureDownInTextControl || !mGestureDownFrameOwner ||
6635 !mGestureDownFrameOwner->IsInNativeAnonymousSubtree()) {
6636 return;
6637 }
6638 // If we track gesture to start drag in aTextControlElement, we should keep
6639 // tracking it with aTextContrlElement itself for now because this may be
6640 // caused by reframing aTextControlElement which may not be intended by the
6641 // user.
6642 if (&aTextControlElement ==
6643 mGestureDownFrameOwner
6644 ->GetClosestNativeAnonymousSubtreeRootParentOrHost()) {
6645 mGestureDownFrameOwner = &aTextControlElement;
6646 }
6647}
6648
6649void EventStateManager::TextControlRootAdded(
6650 Element& aAnonymousDivElement, TextControlElement& aTextControlElement) {
6651 if (!mGestureDownInTextControl ||
6652 mGestureDownFrameOwner != &aTextControlElement) {
6653 return;
6654 }
6655 // If we track gesture to start drag in aTextControlElement, but the frame
6656 // owner is the text control element itself, the anonymous nodes in it are
6657 // recreated by a reframe. If so, we should keep tracking it with the
6658 // recreated native anonymous node.
6659 mGestureDownFrameOwner =
6660 aAnonymousDivElement.GetFirstChild()
6661 ? aAnonymousDivElement.GetFirstChild()
6662 : static_cast<nsIContent*>(&aAnonymousDivElement);
6663}
6664
6665bool EventStateManager::EventStatusOK(WidgetGUIEvent* aEvent) {
6666 return !(aEvent->mMessage == eMouseDown &&
6667 aEvent->AsMouseEvent()->mButton == MouseButton::ePrimary &&
6668 !sNormalLMouseEventInProcess);
6669}
6670
6671//-------------------------------------------
6672// Access Key Registration
6673//-------------------------------------------
6674void EventStateManager::RegisterAccessKey(Element* aElement, uint32_t aKey) {
6675 if (aElement && !mAccessKeys.Contains(aElement)) {
6676 mAccessKeys.AppendObject(aElement);
6677 }
6678}
6679
6680void EventStateManager::UnregisterAccessKey(Element* aElement, uint32_t aKey) {
6681 if (aElement) {
6682 mAccessKeys.RemoveObject(aElement);
6683 }
6684}
6685
6686uint32_t EventStateManager::GetRegisteredAccessKey(Element* aElement) {
6687 MOZ_ASSERT(aElement)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aElement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aElement))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aElement", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6687); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aElement" ")"
); do { *((volatile int*)__null) = 6687; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6688
6689 if (!mAccessKeys.Contains(aElement)) {
6690 return 0;
6691 }
6692
6693 nsAutoString accessKey;
6694 aElement->GetAttr(nsGkAtoms::accesskey, accessKey);
6695 return accessKey.First();
6696}
6697
6698void EventStateManager::EnsureDocument(nsPresContext* aPresContext) {
6699 if (!mDocument) mDocument = aPresContext->Document();
6700}
6701
6702void EventStateManager::FlushLayout(nsPresContext* aPresContext) {
6703 MOZ_ASSERT(aPresContext, "nullptr ptr")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresContext))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPresContext" " ("
"nullptr ptr" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6703); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresContext"
") (" "nullptr ptr" ")"); do { *((volatile int*)__null) = 6703
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
6704 if (RefPtr<PresShell> presShell = aPresContext->GetPresShell()) {
6705 presShell->FlushPendingNotifications(FlushType::InterruptibleLayout);
6706 }
6707}
6708
6709Element* EventStateManager::GetFocusedElement() {
6710 nsFocusManager* fm = nsFocusManager::GetFocusManager();
6711 EnsureDocument(mPresContext);
6712 if (!fm || !mDocument) {
6713 return nullptr;
6714 }
6715
6716 nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
6717 return nsFocusManager::GetFocusedDescendant(
6718 mDocument->GetWindow(), nsFocusManager::eOnlyCurrentWindow,
6719 getter_AddRefs(focusedWindow));
6720}
6721
6722//-------------------------------------------------------
6723// Return true if the docshell is visible
6724
6725bool EventStateManager::IsShellVisible(nsIDocShell* aShell) {
6726 NS_ASSERTION(aShell, "docshell is null")do { if (!(aShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "docshell is null"
, "aShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6726); MOZ_PretendNoReturn(); } } while (0)
;
6727
6728 nsCOMPtr<nsIBaseWindow> basewin = do_QueryInterface(aShell);
6729 if (!basewin) return true;
6730
6731 bool isVisible = true;
6732 basewin->GetVisibility(&isVisible);
6733
6734 // We should be doing some additional checks here so that
6735 // we don't tab into hidden tabs of tabbrowser. -bryner
6736
6737 return isVisible;
6738}
6739
6740nsresult EventStateManager::DoContentCommandEvent(
6741 WidgetContentCommandEvent* aEvent) {
6742 EnsureDocument(mPresContext);
6743 NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(mDocument)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mDocument" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6743); return NS_ERROR_FAILURE; } } while (false)
;
6744 nsCOMPtr<nsPIDOMWindowOuter> window(mDocument->GetWindow());
6745 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(window)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "window" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6745); return NS_ERROR_FAILURE; } } while (false)
;
6746
6747 nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
6748 NS_ENSURE_TRUE(root, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(root)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "root" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6748); return NS_ERROR_FAILURE; } } while (false)
;
6749 const char* cmd;
6750 bool maybeNeedToHandleInRemote = false;
6751 switch (aEvent->mMessage) {
6752 case eContentCommandCut:
6753 cmd = "cmd_cut";
6754 maybeNeedToHandleInRemote = true;
6755 break;
6756 case eContentCommandCopy:
6757 cmd = "cmd_copy";
6758 maybeNeedToHandleInRemote = true;
6759 break;
6760 case eContentCommandPaste:
6761 cmd = "cmd_paste";
6762 maybeNeedToHandleInRemote = true;
6763 break;
6764 case eContentCommandDelete:
6765 cmd = "cmd_delete";
6766 maybeNeedToHandleInRemote = true;
6767 break;
6768 case eContentCommandUndo:
6769 cmd = "cmd_undo";
6770 maybeNeedToHandleInRemote = true;
6771 break;
6772 case eContentCommandRedo:
6773 cmd = "cmd_redo";
6774 maybeNeedToHandleInRemote = true;
6775 break;
6776 case eContentCommandPasteTransferable:
6777 cmd = "cmd_pasteTransferable";
6778 break;
6779 case eContentCommandLookUpDictionary:
6780 cmd = "cmd_lookUpDictionary";
6781 break;
6782 default:
6783 return NS_ERROR_NOT_IMPLEMENTED;
6784 }
6785 if (XRE_IsParentProcess() && maybeNeedToHandleInRemote) {
6786 if (BrowserParent* remote = BrowserParent::GetFocused()) {
6787 if (!aEvent->mOnlyEnabledCheck) {
6788 remote->SendSimpleContentCommandEvent(*aEvent);
6789 }
6790 // XXX The command may be disabled in the parent process. Perhaps, we
6791 // should set actual enabled state in the parent process here and there
6792 // should be another bool flag which indicates whether the content is sent
6793 // to a remote process.
6794 aEvent->mIsEnabled = true;
6795 aEvent->mSucceeded = true;
6796 return NS_OK;
6797 }
6798 }
6799 // If user tries to do something, user must try to do it in visible window.
6800 // So, let's retrieve controller of visible window.
6801 nsCOMPtr<nsIController> controller;
6802 nsresult rv =
6803 root->GetControllerForCommand(cmd, true, getter_AddRefs(controller));
6804 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6804); return rv; } } while (false)
;
6805 if (!controller) {
6806 // When GetControllerForCommand succeeded but there is no controller, the
6807 // command isn't supported.
6808 aEvent->mIsEnabled = false;
6809 } else {
6810 bool canDoIt;
6811 rv = controller->IsCommandEnabled(cmd, &canDoIt);
6812 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6812); return rv; } } while (false)
;
6813 aEvent->mIsEnabled = canDoIt;
6814 if (canDoIt && !aEvent->mOnlyEnabledCheck) {
6815 switch (aEvent->mMessage) {
6816 case eContentCommandPasteTransferable: {
6817 BrowserParent* remote = BrowserParent::GetFocused();
6818 if (remote) {
6819 IPCTransferable ipcTransferable;
6820 nsContentUtils::TransferableToIPCTransferable(
6821 aEvent->mTransferable, &ipcTransferable, false,
6822 remote->Manager());
6823 remote->SendPasteTransferable(std::move(ipcTransferable));
6824 rv = NS_OK;
6825 } else {
6826 nsCOMPtr<nsICommandController> commandController =
6827 do_QueryInterface(controller);
6828 NS_ENSURE_STATE(commandController)do { if ((__builtin_expect(!!(!(commandController)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "commandController" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6828); return NS_ERROR_UNEXPECTED; } } while (false)
;
6829
6830 RefPtr<nsCommandParams> params = new nsCommandParams();
6831 rv = params->SetISupports("transferable", aEvent->mTransferable);
6832 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6832)
) {
6833 return rv;
6834 }
6835 rv = commandController->DoCommandWithParams(cmd, params);
6836 }
6837 break;
6838 }
6839
6840 case eContentCommandLookUpDictionary: {
6841 nsCOMPtr<nsICommandController> commandController =
6842 do_QueryInterface(controller);
6843 if (NS_WARN_IF(!commandController)NS_warn_if_impl(!commandController, "!commandController", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6843)
) {
6844 return NS_ERROR_FAILURE;
6845 }
6846
6847 RefPtr<nsCommandParams> params = new nsCommandParams();
6848 rv = params->SetInt("x", aEvent->mRefPoint.x);
6849 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6849)
) {
6850 return rv;
6851 }
6852
6853 rv = params->SetInt("y", aEvent->mRefPoint.y);
6854 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6854)
) {
6855 return rv;
6856 }
6857
6858 rv = commandController->DoCommandWithParams(cmd, params);
6859 break;
6860 }
6861
6862 default:
6863 rv = controller->DoCommand(cmd);
6864 break;
6865 }
6866 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6866); return rv; } } while (false)
;
6867 }
6868 }
6869 aEvent->mSucceeded = true;
6870 return NS_OK;
6871}
6872
6873nsresult EventStateManager::DoContentCommandInsertTextEvent(
6874 WidgetContentCommandEvent* aEvent) {
6875 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6875); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 6875; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6876 MOZ_ASSERT(aEvent->mMessage == eContentCommandInsertText)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eContentCommandInsertText)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aEvent->mMessage == eContentCommandInsertText))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eContentCommandInsertText"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6876); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eContentCommandInsertText"
")"); do { *((volatile int*)__null) = 6876; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6877 MOZ_DIAGNOSTIC_ASSERT(aEvent->mString.isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mString.isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mString.isSome())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->mString.isSome()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6877); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aEvent->mString.isSome()"
")"); do { *((volatile int*)__null) = 6877; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6878 MOZ_DIAGNOSTIC_ASSERT(!aEvent->mString.ref().IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEvent->mString.ref().IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aEvent->mString.ref().IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aEvent->mString.ref().IsEmpty()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6878); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!aEvent->mString.ref().IsEmpty()"
")"); do { *((volatile int*)__null) = 6878; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6879
6880 aEvent->mIsEnabled = false;
6881 aEvent->mSucceeded = false;
6882
6883 NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(mPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6883); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
6884
6885 if (XRE_IsParentProcess()) {
6886 // Handle it in focused content process if there is.
6887 if (BrowserParent* remote = BrowserParent::GetFocused()) {
6888 if (!aEvent->mOnlyEnabledCheck) {
6889 remote->SendInsertText(*aEvent);
6890 }
6891 // XXX The remote process may be not editable right now. Therefore, this
6892 // may be different from actual state in the remote process.
6893 aEvent->mIsEnabled = true;
6894 aEvent->mSucceeded = true;
6895 return NS_OK;
6896 }
6897 }
6898
6899 // If there is no active editor in this process, we should treat the command
6900 // is disabled.
6901 RefPtr<EditorBase> activeEditor =
6902 nsContentUtils::GetActiveEditor(mPresContext);
6903 if (!activeEditor) {
6904 aEvent->mSucceeded = true;
6905 return NS_OK;
6906 }
6907
6908 nsresult rv = activeEditor->InsertTextAsAction(aEvent->mString.ref());
6909 aEvent->mIsEnabled = rv != NS_SUCCESS_DOM_NO_OPERATION;
6910 aEvent->mSucceeded = NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)));
6911 return NS_OK;
6912}
6913
6914nsresult EventStateManager::DoContentCommandReplaceTextEvent(
6915 WidgetContentCommandEvent* aEvent) {
6916 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6916); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 6916; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6917 MOZ_ASSERT(aEvent->mMessage == eContentCommandReplaceText)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eContentCommandReplaceText)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aEvent->mMessage == eContentCommandReplaceText)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eContentCommandReplaceText"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6917); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eContentCommandReplaceText"
")"); do { *((volatile int*)__null) = 6917; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6918 MOZ_DIAGNOSTIC_ASSERT(aEvent->mString.isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mString.isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mString.isSome())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->mString.isSome()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6918); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aEvent->mString.isSome()"
")"); do { *((volatile int*)__null) = 6918; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6919 MOZ_DIAGNOSTIC_ASSERT(!aEvent->mString.ref().IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEvent->mString.ref().IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aEvent->mString.ref().IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aEvent->mString.ref().IsEmpty()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6919); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!aEvent->mString.ref().IsEmpty()"
")"); do { *((volatile int*)__null) = 6919; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6920
6921 aEvent->mIsEnabled = false;
6922 aEvent->mSucceeded = false;
6923
6924 NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(mPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6924); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
6925
6926 if (XRE_IsParentProcess()) {
6927 // Handle it in focused content process if there is.
6928 if (BrowserParent* remote = BrowserParent::GetFocused()) {
6929 if (!aEvent->mOnlyEnabledCheck) {
6930 Unused << remote->SendReplaceText(*aEvent);
6931 }
6932 // XXX The remote process may be not editable right now. Therefore, this
6933 // may be different from actual state in the remote process.
6934 aEvent->mIsEnabled = true;
6935 aEvent->mSucceeded = true;
6936 return NS_OK;
6937 }
6938 }
6939
6940 // If there is no active editor in this process, we should treat the command
6941 // is disabled.
6942 RefPtr<EditorBase> activeEditor =
6943 nsContentUtils::GetActiveEditor(mPresContext);
6944 if (NS_WARN_IF(!activeEditor)NS_warn_if_impl(!activeEditor, "!activeEditor", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6944)
) {
6945 aEvent->mSucceeded = true;
6946 return NS_OK;
6947 }
6948
6949 RefPtr<TextComposition> composition =
6950 IMEStateManager::GetTextCompositionFor(mPresContext);
6951 if (NS_WARN_IF(composition)NS_warn_if_impl(composition, "composition", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6951)
) {
6952 // We don't support replace text action during composition.
6953 aEvent->mSucceeded = true;
6954 return NS_OK;
6955 }
6956
6957 ContentEventHandler handler(mPresContext);
6958 RefPtr<nsRange> range = handler.GetRangeFromFlatTextOffset(
6959 aEvent, aEvent->mSelection.mOffset,
6960 aEvent->mSelection.mReplaceSrcString.Length());
6961 if (NS_WARN_IF(!range)NS_warn_if_impl(!range, "!range", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6961)
) {
6962 aEvent->mSucceeded = false;
6963 return NS_OK;
6964 }
6965
6966 // If original replacement text isn't matched with selection text, throws
6967 // error.
6968 nsAutoString targetStr;
6969 nsresult rv = handler.GenerateFlatTextContent(range, targetStr);
6970 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6970)
) {
6971 aEvent->mSucceeded = false;
6972 return NS_OK;
6973 }
6974 if (!aEvent->mSelection.mReplaceSrcString.Equals(targetStr)) {
6975 aEvent->mSucceeded = false;
6976 return NS_OK;
6977 }
6978
6979 rv = activeEditor->ReplaceTextAsAction(
6980 aEvent->mString.ref(), range,
6981 TextEditor::AllowBeforeInputEventCancelable::Yes,
6982 aEvent->mSelection.mPreventSetSelection
6983 ? EditorBase::PreventSetSelection::Yes
6984 : EditorBase::PreventSetSelection::No);
6985 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6985)
) {
6986 aEvent->mSucceeded = false;
6987 return NS_OK;
6988 }
6989
6990 aEvent->mIsEnabled = rv != NS_SUCCESS_DOM_NO_OPERATION;
6991 aEvent->mSucceeded = true;
6992 return NS_OK;
6993}
6994
6995nsresult EventStateManager::DoContentCommandScrollEvent(
6996 WidgetContentCommandEvent* aEvent) {
6997 NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(mPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6997); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
6998 PresShell* presShell = mPresContext->GetPresShell();
6999 NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(presShell)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "presShell" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6999); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
7000 NS_ENSURE_TRUE(aEvent->mScroll.mAmount != 0, NS_ERROR_INVALID_ARG)do { if ((__builtin_expect(!!(!(aEvent->mScroll.mAmount !=
0)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE("
"aEvent->mScroll.mAmount != 0" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7000); return NS_ERROR_INVALID_ARG; } } while (false)
;
7001
7002 ScrollUnit scrollUnit;
7003 switch (aEvent->mScroll.mUnit) {
7004 case WidgetContentCommandEvent::eCmdScrollUnit_Line:
7005 scrollUnit = ScrollUnit::LINES;
7006 break;
7007 case WidgetContentCommandEvent::eCmdScrollUnit_Page:
7008 scrollUnit = ScrollUnit::PAGES;
7009 break;
7010 case WidgetContentCommandEvent::eCmdScrollUnit_Whole:
7011 scrollUnit = ScrollUnit::WHOLE;
7012 break;
7013 default:
7014 return NS_ERROR_INVALID_ARG;
7015 }
7016
7017 aEvent->mSucceeded = true;
7018
7019 ScrollContainerFrame* sf =
7020 presShell->GetScrollContainerFrameToScroll(layers::EitherScrollDirection);
7021 aEvent->mIsEnabled =
7022 sf ? (aEvent->mScroll.mIsHorizontal ? WheelHandlingUtils::CanScrollOn(
7023 sf, aEvent->mScroll.mAmount, 0)
7024 : WheelHandlingUtils::CanScrollOn(
7025 sf, 0, aEvent->mScroll.mAmount))
7026 : false;
7027
7028 if (!aEvent->mIsEnabled || aEvent->mOnlyEnabledCheck) {
7029 return NS_OK;
7030 }
7031
7032 nsIntPoint pt(0, 0);
7033 if (aEvent->mScroll.mIsHorizontal) {
7034 pt.x = aEvent->mScroll.mAmount;
7035 } else {
7036 pt.y = aEvent->mScroll.mAmount;
7037 }
7038
7039 // The caller may want synchronous scrolling.
7040 sf->ScrollBy(pt, scrollUnit, ScrollMode::Instant);
7041 return NS_OK;
7042}
7043
7044void EventStateManager::SetActiveManager(EventStateManager* aNewESM,
7045 nsIContent* aContent) {
7046 if (sActiveESM && aNewESM != sActiveESM) {
7047 sActiveESM->SetContentState(nullptr, ElementState::ACTIVE);
7048 }
7049 sActiveESM = aNewESM;
7050 if (sActiveESM && aContent) {
7051 sActiveESM->SetContentState(aContent, ElementState::ACTIVE);
7052 }
7053}
7054
7055void EventStateManager::ClearGlobalActiveContent(EventStateManager* aClearer) {
7056 if (aClearer) {
7057 aClearer->SetContentState(nullptr, ElementState::ACTIVE);
7058 if (sDragOverContent) {
7059 aClearer->SetContentState(nullptr, ElementState::DRAGOVER);
7060 }
7061 }
7062 if (sActiveESM && aClearer != sActiveESM) {
7063 sActiveESM->SetContentState(nullptr, ElementState::ACTIVE);
7064 }
7065 sActiveESM = nullptr;
7066}
7067
7068/******************************************************************/
7069/* mozilla::EventStateManager::DeltaAccumulator */
7070/******************************************************************/
7071
7072void EventStateManager::DeltaAccumulator::InitLineOrPageDelta(
7073 nsIFrame* aTargetFrame, EventStateManager* aESM, WidgetWheelEvent* aEvent) {
7074 MOZ_ASSERT(aESM)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aESM)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aESM))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aESM", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7074); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aESM" ")");
do { *((volatile int*)__null) = 7074; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1
Assuming 'aESM' is non-null
2
Taking false branch
3
Loop condition is false. Exiting loop
7075 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7075); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 7075; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4
Assuming 'aEvent' is non-null
5
Taking false branch
6
Loop condition is false. Exiting loop
7076
7077 // Reset if the previous wheel event is too old.
7078 if (!mLastTime.IsNull()) {
7
Taking true branch
7079 TimeDuration duration = TimeStamp::Now() - mLastTime;
7080 if (duration.ToMilliseconds() >
8
Assuming the condition is false
9
Taking false branch
7081 StaticPrefs::mousewheel_transaction_timeout()) {
7082 Reset();
7083 }
7084 }
7085 // If we have accumulated delta, we may need to reset it.
7086 if (IsInTransaction()) {
10
Taking false branch
7087 // If wheel event type is changed, reset the values.
7088 if (mHandlingDeltaMode != aEvent->mDeltaMode ||
7089 mIsNoLineOrPageDeltaDevice != aEvent->mIsNoLineOrPageDelta) {
7090 Reset();
7091 } else {
7092 // If the delta direction is changed, we should reset only the
7093 // accumulated values.
7094 if (mX && aEvent->mDeltaX && ((aEvent->mDeltaX > 0.0) != (mX > 0.0))) {
7095 mX = mPendingScrollAmountX = 0.0;
7096 }
7097 if (mY && aEvent->mDeltaY && ((aEvent->mDeltaY > 0.0) != (mY > 0.0))) {
7098 mY = mPendingScrollAmountY = 0.0;
7099 }
7100 }
7101 }
7102
7103 mHandlingDeltaMode = aEvent->mDeltaMode;
7104 mIsNoLineOrPageDeltaDevice = aEvent->mIsNoLineOrPageDelta;
7105
7106 {
7107 ScrollContainerFrame* scrollTarget = aESM->ComputeScrollTarget(
12
Calling 'EventStateManager::ComputeScrollTarget'
7108 aTargetFrame, aEvent, COMPUTE_DEFAULT_ACTION_TARGET);
11
Passing value via 1st parameter 'aTargetFrame'
7109 nsPresContext* pc = scrollTarget ? scrollTarget->PresContext()
7110 : aTargetFrame->PresContext();
7111 aEvent->mScrollAmount = aESM->GetScrollAmount(pc, aEvent, scrollTarget);
7112 }
7113
7114 // If it's handling neither a device that does not provide line or page deltas
7115 // nor delta values multiplied by prefs, we must not modify lineOrPageDelta
7116 // values.
7117 // TODO(emilio): Does this care about overridden scroll speed?
7118 if (!mIsNoLineOrPageDeltaDevice &&
7119 !EventStateManager::WheelPrefs::GetInstance()
7120 ->NeedToComputeLineOrPageDelta(aEvent)) {
7121 // Set the delta values to mX and mY. They would be used when above block
7122 // resets mX/mY/mPendingScrollAmountX/mPendingScrollAmountY if the direction
7123 // is changed.
7124 // NOTE: We shouldn't accumulate the delta values, it might could cause
7125 // overflow even though it's not a realistic situation.
7126 if (aEvent->mDeltaX) {
7127 mX = aEvent->mDeltaX;
7128 }
7129 if (aEvent->mDeltaY) {
7130 mY = aEvent->mDeltaY;
7131 }
7132 mLastTime = TimeStamp::Now();
7133 return;
7134 }
7135
7136 mX += aEvent->mDeltaX;
7137 mY += aEvent->mDeltaY;
7138
7139 if (mHandlingDeltaMode == WheelEvent_Binding::DOM_DELTA_PIXEL) {
7140 // Records pixel delta values and init mLineOrPageDeltaX and
7141 // mLineOrPageDeltaY for wheel events which are caused by pixel only
7142 // devices. Ignore mouse wheel transaction for computing this. The
7143 // lineOrPageDelta values will be used by dispatching legacy
7144 // eMouseScrollEventClass (DOMMouseScroll) but not be used for scrolling
7145 // of default action. The transaction should be used only for the default
7146 // action.
7147 auto scrollAmountInCSSPixels =
7148 CSSIntSize::FromAppUnitsRounded(aEvent->mScrollAmount);
7149
7150 aEvent->mLineOrPageDeltaX = RoundDown(mX) / scrollAmountInCSSPixels.width;
7151 aEvent->mLineOrPageDeltaY = RoundDown(mY) / scrollAmountInCSSPixels.height;
7152
7153 mX -= aEvent->mLineOrPageDeltaX * scrollAmountInCSSPixels.width;
7154 mY -= aEvent->mLineOrPageDeltaY * scrollAmountInCSSPixels.height;
7155 } else {
7156 aEvent->mLineOrPageDeltaX = RoundDown(mX);
7157 aEvent->mLineOrPageDeltaY = RoundDown(mY);
7158 mX -= aEvent->mLineOrPageDeltaX;
7159 mY -= aEvent->mLineOrPageDeltaY;
7160 }
7161
7162 mLastTime = TimeStamp::Now();
7163}
7164
7165void EventStateManager::DeltaAccumulator::Reset() {
7166 mX = mY = 0.0;
7167 mPendingScrollAmountX = mPendingScrollAmountY = 0.0;
7168 mHandlingDeltaMode = UINT32_MAX(4294967295U);
7169 mIsNoLineOrPageDeltaDevice = false;
7170}
7171
7172nsIntPoint
7173EventStateManager::DeltaAccumulator::ComputeScrollAmountForDefaultAction(
7174 WidgetWheelEvent* aEvent, const nsIntSize& aScrollAmountInDevPixels) {
7175 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7175); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 7175; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7176
7177 DeltaValues acceleratedDelta = WheelTransaction::AccelerateWheelDelta(aEvent);
7178
7179 nsIntPoint result(0, 0);
7180 if (aEvent->mDeltaMode == WheelEvent_Binding::DOM_DELTA_PIXEL) {
7181 mPendingScrollAmountX += acceleratedDelta.deltaX;
7182 mPendingScrollAmountY += acceleratedDelta.deltaY;
7183 } else {
7184 mPendingScrollAmountX +=
7185 aScrollAmountInDevPixels.width * acceleratedDelta.deltaX;
7186 mPendingScrollAmountY +=
7187 aScrollAmountInDevPixels.height * acceleratedDelta.deltaY;
7188 }
7189 result.x = RoundDown(mPendingScrollAmountX);
7190 result.y = RoundDown(mPendingScrollAmountY);
7191 mPendingScrollAmountX -= result.x;
7192 mPendingScrollAmountY -= result.y;
7193
7194 return result;
7195}
7196
7197/******************************************************************/
7198/* mozilla::EventStateManager::WheelPrefs */
7199/******************************************************************/
7200
7201// static
7202EventStateManager::WheelPrefs* EventStateManager::WheelPrefs::GetInstance() {
7203 if (!sInstance) {
7204 sInstance = new WheelPrefs();
7205 }
7206 return sInstance;
7207}
7208
7209// static
7210void EventStateManager::WheelPrefs::Shutdown() {
7211 delete sInstance;
7212 sInstance = nullptr;
7213}
7214
7215// static
7216void EventStateManager::WheelPrefs::OnPrefChanged(const char* aPrefName,
7217 void* aClosure) {
7218 // forget all prefs, it's not problem for performance.
7219 sInstance->Reset();
7220 DeltaAccumulator::GetInstance()->Reset();
7221}
7222
7223EventStateManager::WheelPrefs::WheelPrefs() {
7224 Reset();
7225 Preferences::RegisterPrefixCallback(OnPrefChanged, "mousewheel.");
7226}
7227
7228EventStateManager::WheelPrefs::~WheelPrefs() {
7229 Preferences::UnregisterPrefixCallback(OnPrefChanged, "mousewheel.");
7230}
7231
7232void EventStateManager::WheelPrefs::Reset() { memset(mInit, 0, sizeof(mInit)); }
7233
7234EventStateManager::WheelPrefs::Index EventStateManager::WheelPrefs::GetIndexFor(
7235 const WidgetWheelEvent* aEvent) {
7236 if (!aEvent) {
7237 return INDEX_DEFAULT;
7238 }
7239
7240 Modifiers modifiers = (aEvent->mModifiers & (MODIFIER_ALT | MODIFIER_CONTROL |
7241 MODIFIER_META | MODIFIER_SHIFT));
7242
7243 switch (modifiers) {
7244 case MODIFIER_ALT:
7245 return INDEX_ALT;
7246 case MODIFIER_CONTROL:
7247 return INDEX_CONTROL;
7248 case MODIFIER_META:
7249 return INDEX_META;
7250 case MODIFIER_SHIFT:
7251 return INDEX_SHIFT;
7252 default:
7253 // If two or more modifier keys are pressed, we should use default
7254 // settings.
7255 return INDEX_DEFAULT;
7256 }
7257}
7258
7259void EventStateManager::WheelPrefs::GetBasePrefName(
7260 EventStateManager::WheelPrefs::Index aIndex, nsACString& aBasePrefName) {
7261 aBasePrefName.AssignLiteral("mousewheel.");
7262 switch (aIndex) {
7263 case INDEX_ALT:
7264 aBasePrefName.AppendLiteral("with_alt.");
7265 break;
7266 case INDEX_CONTROL:
7267 aBasePrefName.AppendLiteral("with_control.");
7268 break;
7269 case INDEX_META:
7270 aBasePrefName.AppendLiteral("with_meta.");
7271 break;
7272 case INDEX_SHIFT:
7273 aBasePrefName.AppendLiteral("with_shift.");
7274 break;
7275 case INDEX_DEFAULT:
7276 default:
7277 aBasePrefName.AppendLiteral("default.");
7278 break;
7279 }
7280}
7281
7282void EventStateManager::WheelPrefs::Init(
7283 EventStateManager::WheelPrefs::Index aIndex) {
7284 if (mInit[aIndex]) {
7285 return;
7286 }
7287 mInit[aIndex] = true;
7288
7289 nsAutoCString basePrefName;
7290 GetBasePrefName(aIndex, basePrefName);
7291
7292 nsAutoCString prefNameX(basePrefName);
7293 prefNameX.AppendLiteral("delta_multiplier_x");
7294 mMultiplierX[aIndex] =
7295 static_cast<double>(Preferences::GetInt(prefNameX.get(), 100)) / 100;
7296
7297 nsAutoCString prefNameY(basePrefName);
7298 prefNameY.AppendLiteral("delta_multiplier_y");
7299 mMultiplierY[aIndex] =
7300 static_cast<double>(Preferences::GetInt(prefNameY.get(), 100)) / 100;
7301
7302 nsAutoCString prefNameZ(basePrefName);
7303 prefNameZ.AppendLiteral("delta_multiplier_z");
7304 mMultiplierZ[aIndex] =
7305 static_cast<double>(Preferences::GetInt(prefNameZ.get(), 100)) / 100;
7306
7307 nsAutoCString prefNameAction(basePrefName);
7308 prefNameAction.AppendLiteral("action");
7309 int32_t action = Preferences::GetInt(prefNameAction.get(), ACTION_SCROLL);
7310 if (action < int32_t(ACTION_NONE) || action > int32_t(ACTION_LAST)) {
7311 NS_WARNING("Unsupported action pref value, replaced with 'Scroll'.")NS_DebugBreak(NS_DEBUG_WARNING, "Unsupported action pref value, replaced with 'Scroll'."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7311)
;
7312 action = ACTION_SCROLL;
7313 }
7314 mActions[aIndex] = static_cast<Action>(action);
7315
7316 // Compute action values overridden by .override_x pref.
7317 // At present, override is possible only for the x-direction
7318 // because this pref is introduced mainly for tilt wheels.
7319 // Note that ACTION_HORIZONTALIZED_SCROLL isn't a valid value for this pref
7320 // because it affects only to deltaY.
7321 prefNameAction.AppendLiteral(".override_x");
7322 int32_t actionOverrideX = Preferences::GetInt(prefNameAction.get(), -1);
7323 if (actionOverrideX < -1 || actionOverrideX > int32_t(ACTION_LAST) ||
7324 actionOverrideX == ACTION_HORIZONTALIZED_SCROLL) {
7325 NS_WARNING("Unsupported action override pref value, didn't override.")NS_DebugBreak(NS_DEBUG_WARNING, "Unsupported action override pref value, didn't override."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7325)
;
7326 actionOverrideX = -1;
7327 }
7328 mOverriddenActionsX[aIndex] = (actionOverrideX == -1)
7329 ? static_cast<Action>(action)
7330 : static_cast<Action>(actionOverrideX);
7331}
7332
7333void EventStateManager::WheelPrefs::GetMultiplierForDeltaXAndY(
7334 const WidgetWheelEvent* aEvent, Index aIndex, double* aMultiplierForDeltaX,
7335 double* aMultiplierForDeltaY) {
7336 *aMultiplierForDeltaX = mMultiplierX[aIndex];
7337 *aMultiplierForDeltaY = mMultiplierY[aIndex];
7338 // If the event has been horizontalized(I.e. treated as a horizontal wheel
7339 // scroll for a vertical wheel scroll), then we should swap mMultiplierX and
7340 // mMultiplierY. By doing this, multipliers will still apply to the delta
7341 // values they origianlly corresponded to.
7342 if (aEvent->mDeltaValuesHorizontalizedForDefaultHandler &&
7343 ComputeActionFor(aEvent) == ACTION_HORIZONTALIZED_SCROLL) {
7344 std::swap(*aMultiplierForDeltaX, *aMultiplierForDeltaY);
7345 }
7346}
7347
7348void EventStateManager::WheelPrefs::ApplyUserPrefsToDelta(
7349 WidgetWheelEvent* aEvent) {
7350 if (aEvent->mCustomizedByUserPrefs) {
7351 return;
7352 }
7353
7354 Index index = GetIndexFor(aEvent);
7355 Init(index);
7356
7357 double multiplierForDeltaX = 1.0, multiplierForDeltaY = 1.0;
7358 GetMultiplierForDeltaXAndY(aEvent, index, &multiplierForDeltaX,
7359 &multiplierForDeltaY);
7360 aEvent->mDeltaX *= multiplierForDeltaX;
7361 aEvent->mDeltaY *= multiplierForDeltaY;
7362 aEvent->mDeltaZ *= mMultiplierZ[index];
7363
7364 // If the multiplier is 1.0 or -1.0, i.e., it doesn't change the absolute
7365 // value, we should use lineOrPageDelta values which were set by widget.
7366 // Otherwise, we need to compute them from accumulated delta values.
7367 if (!NeedToComputeLineOrPageDelta(aEvent)) {
7368 aEvent->mLineOrPageDeltaX *= static_cast<int32_t>(multiplierForDeltaX);
7369 aEvent->mLineOrPageDeltaY *= static_cast<int32_t>(multiplierForDeltaY);
7370 } else {
7371 aEvent->mLineOrPageDeltaX = 0;
7372 aEvent->mLineOrPageDeltaY = 0;
7373 }
7374
7375 aEvent->mCustomizedByUserPrefs =
7376 ((mMultiplierX[index] != 1.0) || (mMultiplierY[index] != 1.0) ||
7377 (mMultiplierZ[index] != 1.0));
7378}
7379
7380void EventStateManager::WheelPrefs::CancelApplyingUserPrefsFromOverflowDelta(
7381 WidgetWheelEvent* aEvent) {
7382 Index index = GetIndexFor(aEvent);
7383 Init(index);
7384
7385 // XXX If the multiplier pref value is negative, the scroll direction was
7386 // changed and caused to scroll different direction. In such case,
7387 // this method reverts the sign of overflowDelta. Does it make widget
7388 // happy? Although, widget can know the pref applied delta values by
7389 // referrencing the deltaX and deltaY of the event.
7390
7391 double multiplierForDeltaX = 1.0, multiplierForDeltaY = 1.0;
7392 GetMultiplierForDeltaXAndY(aEvent, index, &multiplierForDeltaX,
7393 &multiplierForDeltaY);
7394 if (multiplierForDeltaX) {
7395 aEvent->mOverflowDeltaX /= multiplierForDeltaX;
7396 }
7397 if (multiplierForDeltaY) {
7398 aEvent->mOverflowDeltaY /= multiplierForDeltaY;
7399 }
7400}
7401
7402EventStateManager::WheelPrefs::Action
7403EventStateManager::WheelPrefs::ComputeActionFor(
7404 const WidgetWheelEvent* aEvent) {
7405 Index index = GetIndexFor(aEvent);
7406 Init(index);
7407
7408 bool deltaXPreferred = (Abs(aEvent->mDeltaX) > Abs(aEvent->mDeltaY) &&
7409 Abs(aEvent->mDeltaX) > Abs(aEvent->mDeltaZ));
7410 Action* actions = deltaXPreferred ? mOverriddenActionsX : mActions;
7411 if (actions[index] == ACTION_NONE || actions[index] == ACTION_SCROLL ||
7412 actions[index] == ACTION_HORIZONTALIZED_SCROLL) {
7413 return actions[index];
7414 }
7415
7416 // Momentum events shouldn't run special actions.
7417 if (aEvent->mIsMomentum) {
7418 // Use the default action. Note that user might kill the wheel scrolling.
7419 Init(INDEX_DEFAULT);
7420 if (actions[INDEX_DEFAULT] == ACTION_SCROLL ||
7421 actions[INDEX_DEFAULT] == ACTION_HORIZONTALIZED_SCROLL) {
7422 return actions[INDEX_DEFAULT];
7423 }
7424 return ACTION_NONE;
7425 }
7426
7427 return actions[index];
7428}
7429
7430bool EventStateManager::WheelPrefs::NeedToComputeLineOrPageDelta(
7431 const WidgetWheelEvent* aEvent) {
7432 Index index = GetIndexFor(aEvent);
7433 Init(index);
7434
7435 return (mMultiplierX[index] != 1.0 && mMultiplierX[index] != -1.0) ||
7436 (mMultiplierY[index] != 1.0 && mMultiplierY[index] != -1.0);
7437}
7438
7439void EventStateManager::WheelPrefs::GetUserPrefsForEvent(
7440 const WidgetWheelEvent* aEvent, double* aOutMultiplierX,
7441 double* aOutMultiplierY) {
7442 Index index = GetIndexFor(aEvent);
7443 Init(index);
7444
7445 double multiplierForDeltaX = 1.0, multiplierForDeltaY = 1.0;
7446 GetMultiplierForDeltaXAndY(aEvent, index, &multiplierForDeltaX,
7447 &multiplierForDeltaY);
7448 *aOutMultiplierX = multiplierForDeltaX;
7449 *aOutMultiplierY = multiplierForDeltaY;
7450}
7451
7452// static
7453Maybe<layers::APZWheelAction> EventStateManager::APZWheelActionFor(
7454 const WidgetWheelEvent* aEvent) {
7455 if (aEvent->mMessage != eWheel) {
7456 return Nothing();
7457 }
7458 WheelPrefs::Action action =
7459 WheelPrefs::GetInstance()->ComputeActionFor(aEvent);
7460 switch (action) {
7461 case WheelPrefs::ACTION_SCROLL:
7462 case WheelPrefs::ACTION_HORIZONTALIZED_SCROLL:
7463 return Some(layers::APZWheelAction::Scroll);
7464 case WheelPrefs::ACTION_PINCH_ZOOM:
7465 return Some(layers::APZWheelAction::PinchZoom);
7466 default:
7467 return Nothing();
7468 }
7469}
7470
7471// static
7472WheelDeltaAdjustmentStrategy EventStateManager::GetWheelDeltaAdjustmentStrategy(
7473 const WidgetWheelEvent& aEvent) {
7474 if (aEvent.mMessage != eWheel) {
7475 return WheelDeltaAdjustmentStrategy::eNone;
7476 }
7477 switch (WheelPrefs::GetInstance()->ComputeActionFor(&aEvent)) {
7478 case WheelPrefs::ACTION_SCROLL:
7479 if (StaticPrefs::mousewheel_autodir_enabled() && 0 == aEvent.mDeltaZ) {
7480 if (StaticPrefs::mousewheel_autodir_honourroot()) {
7481 return WheelDeltaAdjustmentStrategy::eAutoDirWithRootHonour;
7482 }
7483 return WheelDeltaAdjustmentStrategy::eAutoDir;
7484 }
7485 return WheelDeltaAdjustmentStrategy::eNone;
7486 case WheelPrefs::ACTION_HORIZONTALIZED_SCROLL:
7487 return WheelDeltaAdjustmentStrategy::eHorizontalize;
7488 default:
7489 break;
7490 }
7491 return WheelDeltaAdjustmentStrategy::eNone;
7492}
7493
7494void EventStateManager::GetUserPrefsForWheelEvent(
7495 const WidgetWheelEvent* aEvent, double* aOutMultiplierX,
7496 double* aOutMultiplierY) {
7497 WheelPrefs::GetInstance()->GetUserPrefsForEvent(aEvent, aOutMultiplierX,
7498 aOutMultiplierY);
7499}
7500
7501bool EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedX(
7502 const WidgetWheelEvent* aEvent) {
7503 Index index = GetIndexFor(aEvent);
7504 Init(index);
7505 return Abs(mMultiplierX[index]) >=
7506 MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
7507}
7508
7509bool EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedY(
7510 const WidgetWheelEvent* aEvent) {
7511 Index index = GetIndexFor(aEvent);
7512 Init(index);
7513 return Abs(mMultiplierY[index]) >=
7514 MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
7515}
7516
7517} // namespace mozilla

/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.h

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#ifndef mozilla_EventStateManager_h_
8#define mozilla_EventStateManager_h_
9
10#include "mozilla/EventForwards.h"
11
12#include "nsIObserver.h"
13#include "nsWeakReference.h"
14#include "nsCOMPtr.h"
15#include "nsCOMArray.h"
16#include "nsCycleCollectionParticipant.h"
17#include "nsIWeakReferenceUtils.h"
18#include "nsRefPtrHashtable.h"
19#include "mozilla/Attributes.h"
20#include "mozilla/TimeStamp.h"
21#include "mozilla/layers/APZPublicUtils.h"
22#include "mozilla/dom/Record.h"
23#include "Units.h"
24#include "WheelHandlingHelper.h" // for WheelDeltaAdjustmentStrategy
25
26class nsFrameLoader;
27class nsIContent;
28class nsICookieJarSettings;
29class nsIDocShell;
30class nsIDocShellTreeItem;
31class nsIFrame;
32class imgIContainer;
33class nsIDocumentViewer;
34class nsITimer;
35class nsIWidget;
36class nsPresContext;
37
38enum class FormControlType : uint8_t;
39
40namespace mozilla {
41
42class EditorBase;
43class EnterLeaveDispatcher;
44class IMEContentObserver;
45class ScrollbarsForWheel;
46class ScrollContainerFrame;
47class TextControlElement;
48class WheelTransaction;
49
50namespace dom {
51class DataTransfer;
52class Document;
53class Element;
54class Selection;
55class BrowserParent;
56class RemoteDragStartData;
57
58} // namespace dom
59
60class OverOutElementsWrapper final : public nsISupports {
61 ~OverOutElementsWrapper() = default;
62
63 public:
64 enum class BoundaryEventType : bool { Mouse, Pointer };
65 explicit OverOutElementsWrapper(BoundaryEventType aType) : mType(aType) {}
66
67 NS_DECL_CYCLE_COLLECTING_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: nsCycleCollectingAutoRefCnt mRefCnt; nsAutoOwningThread
_mOwningThread; public: virtual void DeleteCycleCollectable(
void); public:
68 NS_DECL_CYCLE_COLLECTION_CLASS(OverOutElementsWrapper)class cycleCollection : public nsXPCOMCycleCollectionParticipant
{ public: constexpr explicit cycleCollection(Flags aFlags = 0
) : nsXPCOMCycleCollectionParticipant(aFlags) {} private: public
: virtual nsresult TraverseNative(void* p, nsCycleCollectionTraversalCallback
& cb) override; virtual const char* ClassName() override {
return "OverOutElementsWrapper"; }; virtual void DeleteCycleCollectable
(void* p) override { DowncastCCParticipant<OverOutElementsWrapper
>(p)->DeleteCycleCollectable(); } static OverOutElementsWrapper
* Downcast(nsISupports* s) { return static_cast<OverOutElementsWrapper
*>(static_cast<OverOutElementsWrapper*>(s)); } static
nsISupports* Upcast(OverOutElementsWrapper* p) { return static_cast
<nsISupports*>(static_cast<OverOutElementsWrapper*>
(p)); } template <typename T> friend nsISupports* ToSupports
(T* p, cycleCollection* dummy); virtual void Unlink(void* p) override
; static constexpr nsXPCOMCycleCollectionParticipant* GetParticipant
() { return &OverOutElementsWrapper::_cycleCollectorGlobal
; } }; virtual void CheckForRightParticipant() { nsXPCOMCycleCollectionParticipant
* p; CallQueryInterface(this, &p); do { static_assert( mozilla
::detail::AssertionConditionType<decltype(p == &_cycleCollectorGlobal
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(p == &_cycleCollectorGlobal))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("p == &_cycleCollectorGlobal"
" (" "OverOutElementsWrapper" " should QI to its own CC participant"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.h"
, 68); AnnotateMozCrashReason("MOZ_ASSERT" "(" "p == &_cycleCollectorGlobal"
") (" "OverOutElementsWrapper" " should QI to its own CC participant"
")"); do { *((volatile int*)__null) = 68; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } static cycleCollection
_cycleCollectorGlobal; virtual void BaseCycleCollectable() final
{}
69
70 already_AddRefed<nsIWidget> GetLastOverWidget() const;
71
72 void ContentRemoved(nsIContent& aContent);
73 void WillDispatchOverAndEnterEvent(nsIContent* aOverEventTarget);
74 void DidDispatchOverAndEnterEvent(
75 nsIContent* aOriginalOverTargetInComposedDoc,
76 nsIWidget* aOverEventTargetWidget);
77 [[nodiscard]] bool IsDispatchingOverEventOn(
78 nsIContent* aOverEventTarget) const {
79 MOZ_ASSERT(aOverEventTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aOverEventTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aOverEventTarget))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aOverEventTarget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.h"
, 79); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aOverEventTarget"
")"); do { *((volatile int*)__null) = 79; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
80 return LastOverEventTargetIsOutEventTarget() &&
81 mDeepestEnterEventTarget == aOverEventTarget;
82 }
83 void WillDispatchOutAndOrLeaveEvent() {
84 // Store the first "out" event target or the deepest "leave" event target
85 // which we fire and don't refire "out" event to that element while the
86 // first "out" event is still ongoing.
87 mDispatchingOutOrDeepestLeaveEventTarget = mDeepestEnterEventTarget;
88 }
89 void DidDispatchOutAndOrLeaveEvent() {
90 StoreOverEventTargetAndDeepestEnterEventTarget(nullptr);
91 mDispatchingOutOrDeepestLeaveEventTarget = nullptr;
92 }
93 [[nodiscard]] bool IsDispatchingOutEventOnLastOverEventTarget() const {
94 return mDispatchingOutOrDeepestLeaveEventTarget &&
95 mDispatchingOutOrDeepestLeaveEventTarget == mDeepestEnterEventTarget;
96 }
97 void OverrideOverEventTarget(nsIContent* aOverEventTarget) {
98 StoreOverEventTargetAndDeepestEnterEventTarget(aOverEventTarget);
99 // We don't need the widget for aOverEventTarget because this method is used
100 // for adjusting the "over" event target for the following "out" event
101 // dispatch.
102 mLastOverWidget = nullptr;
103 }
104
105 [[nodiscard]] nsIContent* GetDeepestLeaveEventTarget() const {
106 // The last deepest "enter" event targe (it may be same as the last "over"
107 // target) is the deepest "leave" event target.
108 return mDeepestEnterEventTarget;
109 }
110 [[nodiscard]] nsIContent* GetOutEventTarget() const {
111 // The last deepest "enter" event target is same as the "over" event target
112 // unless it's never been removed from the DOM tree. If and only if the
113 // last "over" event target has not been removed from the DOM tree, it's
114 // the next "out" event target. Once the last "over" target is removed,
115 // "out" event should not be fired on the target nor its ancestor.
116 return LastOverEventTargetIsOutEventTarget()
117 ? mDeepestEnterEventTarget.get()
118 : nullptr;
119 }
120
121 /**
122 * Called when EventStateManager::PreHandleEvent() receives an event which
123 * should be treated as the deadline to restore the last "over" event target
124 * as the next "out" event target and for avoiding to dispatch redundant
125 * "over" event on the same target again when it was removed but reconnected.
126 * If the last "over" event target was reconnected under the last deepest
127 * "enter" event target, this restores the last "over" event target.
128 * Otherwise, makes the instance forget the last "over" target because the
129 * user maybe has seen that the last "over" target is completely removed from
130 * the tree.
131 *
132 * @param aEvent The event which the caller received. If this is set to
133 * nullptr or not a mouse event, this forgets the pending
134 * last "over" event target.
135 */
136 void TryToRestorePendingRemovedOverTarget(const WidgetEvent* aEvent);
137
138 /**
139 * Return true if we have a pending removing last "over" event target at least
140 * for the weak reference to it. In other words, when this returns true, we
141 * need to handle the pending removing "over" event target.
142 */
143 [[nodiscard]] bool MaybeHasPendingRemovingOverEventTarget() const {
144 return mPendingRemovingOverEventTarget;
145 }
146
147 private:
148 /**
149 * Whether the last "over" event target is the target of "out" event if you
150 * dispatch "out" event.
151 */
152 [[nodiscard]] bool LastOverEventTargetIsOutEventTarget() const {
153 MOZ_ASSERT_IF(mDeepestEnterEventTargetIsOverEventTarget,do { if (mDeepestEnterEventTargetIsOverEventTarget) { 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.h"
, 154); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget"
")"); do { *((volatile int*)__null) = 154; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
154 mDeepestEnterEventTarget)do { if (mDeepestEnterEventTargetIsOverEventTarget) { 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.h"
, 154); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget"
")"); do { *((volatile int*)__null) = 154; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
155 MOZ_ASSERT_IF(mDeepestEnterEventTargetIsOverEventTarget,do { if (mDeepestEnterEventTargetIsOverEventTarget) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(!MaybeHasPendingRemovingOverEventTarget
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!MaybeHasPendingRemovingOverEventTarget()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!MaybeHasPendingRemovingOverEventTarget()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.h"
, 156); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!MaybeHasPendingRemovingOverEventTarget()"
")"); do { *((volatile int*)__null) = 156; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
156 !MaybeHasPendingRemovingOverEventTarget())do { if (mDeepestEnterEventTargetIsOverEventTarget) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(!MaybeHasPendingRemovingOverEventTarget
())>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!MaybeHasPendingRemovingOverEventTarget()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!MaybeHasPendingRemovingOverEventTarget()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.h"
, 156); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!MaybeHasPendingRemovingOverEventTarget()"
")"); do { *((volatile int*)__null) = 156; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
157 return mDeepestEnterEventTargetIsOverEventTarget;
158 }
159
160 void StoreOverEventTargetAndDeepestEnterEventTarget(
161 nsIContent* aOverEventTargetAndDeepestEnterEventTarget);
162 void UpdateDeepestEnterEventTarget(nsIContent* aDeepestEnterEventTarget);
163
164 nsCOMPtr<nsIContent> GetPendingRemovingOverEventTarget() const {
165 nsCOMPtr<nsIContent> pendingRemovingOverEventTarget =
166 do_QueryReferent(mPendingRemovingOverEventTarget);
167 return pendingRemovingOverEventTarget.forget();
168 }
169
170 // The deepest event target of the last "enter" event. If
171 // mDeepestEnterEventTargetIsOverEventTarget is true, this is the last "over"
172 // event target too. If it's set to false, this is an ancestor of the last
173 // "over" event target which is not removed from the DOM tree.
174 nsCOMPtr<nsIContent> mDeepestEnterEventTarget;
175
176 // The last "over" event target which will be considered as disconnected or
177 // connected later because web apps may remove the "over" event target
178 // temporarily and reconnect it to the deepest "enter" target immediately.
179 // In such case, we should keep treating it as the last "over" event target
180 // as the next "out" event target.
181 // FYI: This needs to be a weak pointer. Otherwise, the leak window checker
182 // of mochitests will detect windows in the closed tabs which ran tests
183 // synthesizing mouse moves because while a <browser> is stored with a strong
184 // pointer, the child window is also grabbed by the element.
185 nsWeakPtr mPendingRemovingOverEventTarget;
186
187 // While we're dispatching "over" and "enter" events, this is set to the
188 // "over" event target. If it's removed from the DOM tree, this is set to
189 // nullptr.
190 nsCOMPtr<nsIContent> mDispatchingOverEventTarget;
191
192 // While we're dispatching "out" and/or "leave" events, this is set to the
193 // "out" event target or the deepest leave event target. If it's removed from
194 // the DOM tree, this is set to nullptr.
195 nsCOMPtr<nsIContent> mDispatchingOutOrDeepestLeaveEventTarget;
196
197 // The widget on which we dispatched the last "over" event. Note that
198 // nsIWidget is not cycle collectable. Therefore, for avoiding unexpected
199 // memory leaks, we use nsWeakPtr to store the widget here.
200 nsWeakPtr mLastOverWidget;
201
202 const BoundaryEventType mType;
203
204 // Once the last "over" element is removed from the tree, this is set
205 // to false. Then, mDeepestEnterEventTarget may be an ancestor of the
206 // "over" element which should be the deepest target of next "leave"
207 // element but shouldn't be target of "out" event.
208 bool mDeepestEnterEventTargetIsOverEventTarget = false;
209};
210
211class EventStateManager : public nsSupportsWeakReference, public nsIObserver {
212 friend class mozilla::EnterLeaveDispatcher;
213 friend class mozilla::ScrollbarsForWheel;
214 friend class mozilla::WheelTransaction;
215
216 using ElementState = dom::ElementState;
217
218 virtual ~EventStateManager();
219
220 public:
221 EventStateManager();
222
223 NS_DECL_CYCLE_COLLECTING_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: nsCycleCollectingAutoRefCnt mRefCnt; nsAutoOwningThread
_mOwningThread; public: virtual void DeleteCycleCollectable(
void); public:
224 NS_DECL_NSIOBSERVERvirtual nsresult Observe(nsISupports *aSubject, const char * aTopic
, const char16_t * aData) override;
225
226 nsresult Init();
227 nsresult Shutdown();
228
229 /* The PreHandleEvent method is called before event dispatch to either
230 * the DOM or frames. Any processing which must not be prevented or
231 * cancelled should occur here. Any processing which is intended to
232 * be conditional based on either DOM or frame processing should occur in
233 * PostHandleEvent. Any centralized event processing which must occur before
234 * DOM or frame event handling should occur here as well.
235 *
236 * aOverrideClickTarget can be used to indicate which element should be
237 * used as the *up target when deciding whether to send click event.
238 * This is used when releasing pointer capture. Otherwise null.
239 */
240 MOZ_CAN_RUN_SCRIPT
241 nsresult PreHandleEvent(nsPresContext* aPresContext, WidgetEvent* aEvent,
242 nsIFrame* aTargetFrame, nsIContent* aTargetContent,
243 nsEventStatus* aStatus,
244 nsIContent* aOverrideClickTarget);
245
246 /* The PostHandleEvent method should contain all system processing which
247 * should occur conditionally based on DOM or frame processing. It should
248 * also contain any centralized event processing which must occur after
249 * DOM and frame processing.
250 */
251 MOZ_CAN_RUN_SCRIPT
252 nsresult PostHandleEvent(nsPresContext* aPresContext, WidgetEvent* aEvent,
253 nsIFrame* aTargetFrame, nsEventStatus* aStatus,
254 nsIContent* aOverrideClickTarget);
255
256 MOZ_CAN_RUN_SCRIPT void PostHandleKeyboardEvent(
257 WidgetKeyboardEvent* aKeyboardEvent, nsIFrame* aTargetFrame,
258 nsEventStatus& aStatus);
259
260 /**
261 * DispatchLegacyMouseScrollEvents() dispatches eLegacyMouseLineOrPageScroll
262 * event and eLegacyMousePixelScroll event for compatibility with old Gecko.
263 */
264 MOZ_CAN_RUN_SCRIPT_BOUNDARY void DispatchLegacyMouseScrollEvents(
265 nsIFrame* aTargetFrame, WidgetWheelEvent* aEvent, nsEventStatus* aStatus);
266
267 MOZ_CAN_RUN_SCRIPT_BOUNDARY void NotifyDestroyPresContext(
268 nsPresContext* aPresContext);
269
270 void ResetHoverState();
271
272 void SetPresContext(nsPresContext* aPresContext);
273 void ClearFrameRefs(nsIFrame* aFrame);
274
275 nsIFrame* GetEventTarget();
276 already_AddRefed<nsIContent> GetEventTargetContent(WidgetEvent* aEvent);
277
278 // We manage 4 states here: ACTIVE, HOVER, DRAGOVER, URLTARGET
279 static bool ManagesState(ElementState aState) {
280 return aState == ElementState::ACTIVE || aState == ElementState::HOVER ||
281 aState == ElementState::DRAGOVER ||
282 aState == ElementState::URLTARGET;
283 }
284
285 /**
286 * Notify that the given ElementState::* bit has changed for this content.
287 * @param aContent Content which has changed states
288 * @param aState Corresponding state flags such as ElementState::FOCUS
289 * @return Whether the content was able to change all states. Returns false
290 * if a resulting DOM event causes the content node passed in
291 * to not change states. Note, the frame for the content may
292 * change as a result of the content state change, because of
293 * frame reconstructions that may occur, but this does not
294 * affect the return value.
295 */
296 bool SetContentState(nsIContent* aContent, ElementState aState);
297
298 nsIContent* GetActiveContent() const { return mActiveContent; }
299
300 void NativeAnonymousContentRemoved(nsIContent* aAnonContent);
301 MOZ_CAN_RUN_SCRIPT_BOUNDARY void ContentRemoved(dom::Document* aDocument,
302 nsIContent* aContent);
303
304 /**
305 * Called when a native anonymous <div> element which is root element of
306 * text editor will be removed.
307 */
308 void TextControlRootWillBeRemoved(TextControlElement& aTextControlElement);
309
310 /**
311 * Called when a native anonymous <div> element which is root element of
312 * text editor is created.
313 */
314 void TextControlRootAdded(dom::Element& aAnonymousDivElement,
315 TextControlElement& aTextControlElement);
316
317 bool EventStatusOK(WidgetGUIEvent* aEvent);
318
319 /**
320 * EventStateManager stores IMEContentObserver while it's observing contents.
321 * Following mehtods are called by IMEContentObserver when it starts to
322 * observe or stops observing the content.
323 */
324 void OnStartToObserveContent(IMEContentObserver* aIMEContentObserver);
325 void OnStopObservingContent(IMEContentObserver* aIMEContentObserver);
326
327 /**
328 * TryToFlushPendingNotificationsToIME() suggests flushing pending
329 * notifications to IME to IMEContentObserver.
330 * Doesn't do anything in child processes where flushing happens
331 * asynchronously.
332 */
333 void TryToFlushPendingNotificationsToIME();
334
335 static bool IsKeyboardEventUserActivity(WidgetEvent* aEvent);
336
337 /**
338 * Register accesskey on the given element. When accesskey is activated then
339 * the element will be notified via Element::PerformAccesskey() method.
340 *
341 * @param aElement the given element
342 * @param aKey accesskey
343 */
344 void RegisterAccessKey(dom::Element* aElement, uint32_t aKey);
345
346 /**
347 * Unregister accesskey for the given element.
348 *
349 * @param aElement the given element
350 * @param aKey accesskey
351 */
352 void UnregisterAccessKey(dom::Element* aElement, uint32_t aKey);
353
354 /**
355 * Get accesskey registered on the given element or 0 if there is none.
356 *
357 * @param aElement the given element (must not be null)
358 * @return registered accesskey
359 */
360 uint32_t GetRegisteredAccessKey(dom::Element* aContent);
361
362 static void GetAccessKeyLabelPrefix(dom::Element* aElement,
363 nsAString& aPrefix);
364
365 /**
366 * HandleAccessKey() looks for access keys which matches with aEvent and
367 * execute when it matches with a chrome access key or some content access
368 * keys.
369 * If the event may match chrome access keys, this handles the access key
370 * synchronously (if there are nested ESMs, their HandleAccessKey() are
371 * also called recursively).
372 * If the event may match content access keys and focused target is a remote
373 * process, this does nothing for the content because when this is called,
374 * it should already have been handled in the remote process.
375 * If the event may match content access keys and focused target is not in
376 * remote process but there are some remote children, this will post
377 * HandleAccessKey messages to all remote children.
378 *
379 * @return true if there is accesskey which aEvent and
380 * aAccessCharCodes match with. Otherwise, false.
381 * I.e., when this returns true, a target is executed
382 * or focused.
383 * Note that even if this returns false, a target in
384 * remote process may be executed or focused
385 * asynchronously.
386 */
387 bool HandleAccessKey(WidgetKeyboardEvent* aEvent, nsPresContext* aPresContext,
388 nsTArray<uint32_t>& aAccessCharCodes) {
389 return WalkESMTreeToHandleAccessKey(aEvent, aPresContext, aAccessCharCodes,
390 nullptr, eAccessKeyProcessingNormal,
391 true);
392 }
393
394 /**
395 * CheckIfEventMatchesAccessKey() looks for access key which matches with
396 * aEvent in the process but won't execute it.
397 *
398 * @return true if there is accesskey which aEvent matches with
399 * in this process. Otherwise, false.
400 */
401 bool CheckIfEventMatchesAccessKey(WidgetKeyboardEvent* aEvent,
402 nsPresContext* aPresContext);
403
404 nsresult SetCursor(StyleCursorKind, imgIContainer*, const ImageResolution&,
405 const Maybe<gfx::IntPoint>& aHotspot, nsIWidget* aWidget,
406 bool aLockCursor);
407
408 void StartHidingCursorWhileTyping(nsIWidget*);
409
410 /**
411 * Checks if the current mouse over element matches the given
412 * Element (which has a remote frame), and if so, notifies
413 * the BrowserParent of the mouse enter.
414 * Called when we reconstruct the BrowserParent and need to
415 * recompute state on the new object.
416 */
417 void RecomputeMouseEnterStateForRemoteFrame(dom::Element& aElement);
418
419 nsPresContext* GetPresContext() { return mPresContext; }
420
421 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(EventStateManager, nsIObserver)class cycleCollection : public nsXPCOMCycleCollectionParticipant
{ public: constexpr explicit cycleCollection(Flags aFlags = 0
) : nsXPCOMCycleCollectionParticipant(aFlags) {} private: public
: virtual nsresult TraverseNative(void* p, nsCycleCollectionTraversalCallback
& cb) override; virtual const char* ClassName() override {
return "EventStateManager"; }; virtual void DeleteCycleCollectable
(void* p) override { DowncastCCParticipant<EventStateManager
>(p)->DeleteCycleCollectable(); } static EventStateManager
* Downcast(nsISupports* s) { return static_cast<EventStateManager
*>(static_cast<nsIObserver*>(s)); } static nsISupports
* Upcast(EventStateManager* p) { return static_cast<nsISupports
*>(static_cast<nsIObserver*>(p)); } template <typename
T> friend nsISupports* ToSupports(T* p, cycleCollection* dummy
); virtual void Unlink(void* p) override; static constexpr nsXPCOMCycleCollectionParticipant
* GetParticipant() { return &EventStateManager::_cycleCollectorGlobal
; } }; virtual void CheckForRightParticipant() { nsXPCOMCycleCollectionParticipant
* p; CallQueryInterface(this, &p); do { static_assert( mozilla
::detail::AssertionConditionType<decltype(p == &_cycleCollectorGlobal
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(p == &_cycleCollectorGlobal))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("p == &_cycleCollectorGlobal"
" (" "EventStateManager" " should QI to its own CC participant"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.h"
, 421); AnnotateMozCrashReason("MOZ_ASSERT" "(" "p == &_cycleCollectorGlobal"
") (" "EventStateManager" " should QI to its own CC participant"
")"); do { *((volatile int*)__null) = 421; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } static cycleCollection
_cycleCollectorGlobal; virtual void BaseCycleCollectable() final
{}
422
423 // The manager in this process that is setting the cursor. In the parent
424 // process it might be null if a remote process is setting the cursor.
425 static EventStateManager* sCursorSettingManager;
426 static void ClearCursorSettingManager() { sCursorSettingManager = nullptr; }
427
428 // Checks if the manager in this process has a locked cursor
429 static bool CursorSettingManagerHasLockedCursor();
430
431 static EventStateManager* GetActiveEventStateManager() { return sActiveESM; }
432
433 // Sets aNewESM to be the active event state manager, and
434 // if aContent is non-null, marks the object as active.
435 static void SetActiveManager(EventStateManager* aNewESM,
436 nsIContent* aContent);
437
438 static bool IsRemoteTarget(nsIContent* target);
439
440 static bool IsTopLevelRemoteTarget(nsIContent* aTarget);
441
442 // Returns the kind of APZ action the given WidgetWheelEvent will perform.
443 static Maybe<layers::APZWheelAction> APZWheelActionFor(
444 const WidgetWheelEvent* aEvent);
445
446 // For some kinds of scrollings, the delta values of WidgetWheelEvent are
447 // possbile to be adjusted. This function is used to detect such scrollings
448 // and returns a wheel delta adjustment strategy to use, which is corresponded
449 // to the kind of the scrolling.
450 // It returns WheelDeltaAdjustmentStrategy::eAutoDir if the current default
451 // action is auto-dir scrolling which honours the scrolling target(The
452 // comments in WheelDeltaAdjustmentStrategy describes the concept in detail).
453 // It returns WheelDeltaAdjustmentStrategy::eAutoDirWithRootHonour if the
454 // current action is auto-dir scrolling which honours the root element in the
455 // document where the scrolling target is(The comments in
456 // WheelDeltaAdjustmentStrategy describes the concept in detail).
457 // It returns WheelDeltaAdjustmentStrategy::eHorizontalize if the current
458 // default action is horizontalized scrolling.
459 // It returns WheelDeltaAdjustmentStrategy::eNone to mean no delta adjustment
460 // strategy should be used if the scrolling is just a tranditional scrolling
461 // whose delta values are never possible to be adjusted.
462 static WheelDeltaAdjustmentStrategy GetWheelDeltaAdjustmentStrategy(
463 const WidgetWheelEvent& aEvent);
464
465 // Returns user-set multipliers for a wheel event.
466 static void GetUserPrefsForWheelEvent(const WidgetWheelEvent* aEvent,
467 double* aOutMultiplierX,
468 double* aOutMultiplierY);
469
470 // Holds the point in screen coords that a mouse event was dispatched to,
471 // before we went into pointer lock mode. This is constantly updated while
472 // the pointer is not locked, but we don't update it while the pointer is
473 // locked. This is used by dom::Event::GetScreenCoords() to make mouse
474 // events' screen coord appear frozen at the last mouse position while
475 // the pointer is locked.
476 static CSSIntPoint sLastScreenPoint;
477
478 // Holds the point in client coords of the last mouse event. Used by
479 // dom::Event::GetClientCoords() to make mouse events' client coords appear
480 // frozen at the last mouse position while the pointer is locked.
481 static CSSIntPoint sLastClientPoint;
482
483 /**
484 * If the absolute values of mMultiplierX and/or mMultiplierY are equal or
485 * larger than this value, the computed scroll amount isn't rounded down to
486 * the page width or height.
487 */
488 static constexpr double MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL =
489 1000.0;
490
491 /**
492 * HandleMiddleClickPaste() handles middle mouse button event as pasting
493 * clipboard text. Note that if aEditorBase is nullptr, this only
494 * dispatches ePaste event because it's necessary for some web apps which
495 * want to implement their own editor and supports middle click paste.
496 *
497 * @param aPresShell The PresShell for the ESM. This lifetime
498 * should be guaranteed by the caller.
499 * @param aMouseEvent The ePointerClick event which caused the
500 * paste.
501 * @param aStatus The event status of aMouseEvent.
502 * @param aEditorBase EditorBase which may be pasted the
503 * clipboard text by the middle click.
504 * If there is no editor for aMouseEvent,
505 * set nullptr.
506 */
507 MOZ_CAN_RUN_SCRIPT
508 nsresult HandleMiddleClickPaste(PresShell* aPresShell,
509 WidgetMouseEvent* aMouseEvent,
510 nsEventStatus* aStatus,
511 EditorBase* aEditorBase);
512
513 static void ConsumeInteractionData(
514 dom::Record<nsString, dom::InteractionData>& aInteractions);
515
516 // Stop tracking a possible drag. If aClearInChildProcesses is true, send
517 // a notification to any child processes that are in the drag service that
518 // tried to start a drag.
519 void StopTrackingDragGesture(bool aClearInChildProcesses);
520
521 protected:
522 /*
523 * If aTargetFrame's widget has a cached cursor value, resets the cursor
524 * such that the next call to SetCursor on the widget will force an update
525 * of the native cursor. For use in getting puppet widget to update its
526 * cursor between mouse exit / enter transitions. This call basically wraps
527 * nsIWidget ClearCachedCursor.
528 */
529 void ClearCachedWidgetCursor(nsIFrame* aTargetFrame);
530
531 void UpdateCursor(nsPresContext*, WidgetMouseEvent*, nsIFrame* aTargetFrame,
532 nsEventStatus* aStatus);
533 /**
534 * Turn a GUI mouse/pointer event into a mouse/pointer event targeted at the
535 * specified content.
536 *
537 * @return widget which is the nearest widget from the event target frame.
538 */
539 [[nodiscard]] MOZ_CAN_RUN_SCRIPT already_AddRefed<nsIWidget>
540 DispatchMouseOrPointerBoundaryEvent(WidgetMouseEvent* aMouseEvent,
541 EventMessage aMessage,
542 nsIContent* aTargetContent,
543 nsIContent* aRelatedContent);
544 /**
545 * Synthesize DOM pointerover and pointerout events
546 */
547 void GeneratePointerEnterExit(EventMessage aMessage,
548 WidgetMouseEvent* aEvent);
549 /**
550 * Synthesize DOM and frame mouseover and mouseout events from this
551 * MOUSE_MOVE or MOUSE_EXIT event.
552 */
553 void GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent);
554 /**
555 * Tell this ESM and ESMs in parent documents that the mouse is
556 * over some content in this document.
557 */
558 MOZ_CAN_RUN_SCRIPT_BOUNDARY void NotifyMouseOver(
559 WidgetMouseEvent* aMouseEvent, nsIContent* aContent);
560 /**
561 * Tell this ESM and ESMs in affected child documents that the mouse
562 * has exited this document's currently hovered content.
563 * TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
564 *
565 * @param aMouseEvent the event that triggered the mouseout
566 * @param aMovingInto the content node we've moved into. This is used to set
567 * the relatedTarget for mouseout events. Also, if it's non-null
568 * NotifyMouseOut will NOT change the current hover content to null;
569 * in that case the caller is responsible for updating hover state.
570 */
571 MOZ_CAN_RUN_SCRIPT_BOUNDARY void NotifyMouseOut(WidgetMouseEvent* aMouseEvent,
572 nsIContent* aMovingInto);
573 MOZ_CAN_RUN_SCRIPT void GenerateDragDropEnterExit(
574 nsPresContext* aPresContext, WidgetDragEvent* aDragEvent);
575
576 /**
577 * Return mMouseEnterLeaveHelper or relevant mPointersEnterLeaveHelper
578 * elements wrapper. If mPointersEnterLeaveHelper does not contain wrapper for
579 * pointerId it create new one
580 */
581 OverOutElementsWrapper* GetWrapperByEventID(WidgetMouseEvent* aMouseEvent);
582
583 /**
584 * Fire the dragenter and dragexit/dragleave events when the mouse moves to a
585 * new target.
586 *
587 * @param aRelatedTarget relatedTarget to set for the event
588 * @param aTargetContent target to set for the event
589 * @param aTargetFrame target frame for the event
590 */
591 MOZ_CAN_RUN_SCRIPT void FireDragEnterOrExit(nsPresContext* aPresContext,
592 WidgetDragEvent* aDragEvent,
593 EventMessage aMessage,
594 nsIContent* aRelatedTarget,
595 nsIContent* aTargetContent,
596 AutoWeakFrame& aTargetFrame);
597 /**
598 * Update the initial drag session data transfer with any changes that occur
599 * on cloned data transfer objects used for events.
600 */
601 void UpdateDragDataTransfer(WidgetDragEvent* dragEvent);
602
603 /**
604 * InitAndDispatchClickEvent() dispatches a click event.
605 *
606 * @param aMouseUpEvent eMouseUp event which causes the click event.
607 * EventCausesClickEvents() must return true
608 * if this event is set to it.
609 * @param aStatus Returns the result of click event.
610 * If the status indicates consumed, the
611 * value won't be overwritten with
612 * nsEventStatus_eIgnore.
613 * @param aMessage Should be ePointerClick, eMouseDoubleClick
614 * or ePointerAuxClick.
615 * @param aPresShell The PresShell.
616 * @param aMouseUpContent The event target of aMouseUpEvent.
617 * @param aCurrentTarget Current target of the caller.
618 * @param aNoContentDispatch true if the event shouldn't be exposed to
619 * web contents (although will be fired on
620 * document and window).
621 * @param aOverrideClickTarget Preferred click event target. If this is
622 * not nullptr, aMouseUpContent and
623 * aCurrentTarget are ignored.
624 */
625 MOZ_CAN_RUN_SCRIPT
626 static nsresult InitAndDispatchClickEvent(
627 WidgetMouseEvent* aMouseUpEvent, nsEventStatus* aStatus,
628 EventMessage aMessage, PresShell* aPresShell, nsIContent* aMouseUpContent,
629 AutoWeakFrame aCurrentTarget, bool aNoContentDispatch,
630 nsIContent* aOverrideClickTarget);
631
632 nsresult SetClickCount(WidgetMouseEvent* aEvent, nsEventStatus* aStatus,
633 nsIContent* aOverrideClickTarget = nullptr);
634
635 /**
636 * EventCausesClickEvents() returns true when aMouseEvent is an eMouseUp
637 * event and it should cause ePointerClick, eMouseDoubleClick and/or
638 * ePointerAuxClick events. Note that this method assumes that
639 * aMouseEvent.mClickCount has already been initialized with SetClickCount().
640 */
641 static bool EventCausesClickEvents(const WidgetMouseEvent& aMouseEvent);
642
643 /**
644 * PostHandleMouseUp() handles default actions of eMouseUp event.
645 *
646 * @param aMouseUpEvent eMouseUp event which causes the click event.
647 * EventCausesClickEvents() must return true
648 * if this event is set to it.
649 * @param aStatus Returns the result of event status.
650 * If one of dispatching event is consumed or
651 * this does something as default action,
652 * returns nsEventStatus_eConsumeNoDefault.
653 * @param aOverrideClickTarget Preferred click event target. If nullptr,
654 * aMouseUpEvent target and current target
655 * are used.
656 */
657 MOZ_CAN_RUN_SCRIPT
658 nsresult PostHandleMouseUp(WidgetMouseEvent* aMouseUpEvent,
659 nsEventStatus* aStatus,
660 nsIContent* aOverrideClickTarget);
661
662 /**
663 * DispatchClickEvents() dispatches ePointerClick, eMouseDoubleClick and
664 * ePointerAuxClick events for aMouseUpEvent. aMouseUpEvent should cause
665 * click event.
666 *
667 * @param aPresShell The PresShell.
668 * @param aMouseUpEvent eMouseUp event which causes the click event.
669 * EventCausesClickEvents() must return true
670 * if this event is set to it.
671 * @param aStatus Returns the result of event status.
672 * If one of dispatching click event is
673 * consumed, returns
674 * nsEventStatus_eConsumeNoDefault.
675 * @param aMouseUpContent The event target of aMouseUpEvent.
676 * @param aOverrideClickTarget Preferred click event target. If this is
677 * not nullptr, aMouseUpContent and
678 * current target frame of the ESM are ignored.
679 */
680 MOZ_CAN_RUN_SCRIPT
681 nsresult DispatchClickEvents(PresShell* aPresShell,
682 WidgetMouseEvent* aMouseUpEvent,
683 nsEventStatus* aStatus,
684 nsIContent* aMouseUpContent,
685 nsIContent* aOverrideClickTarget);
686
687 void EnsureDocument(nsPresContext* aPresContext);
688 MOZ_CAN_RUN_SCRIPT_BOUNDARY
689 void FlushLayout(nsPresContext* aPresContext);
690
691 /**
692 * The phases of WalkESMTreeToHandleAccessKey processing. See below.
693 */
694 enum ProcessingAccessKeyState {
695 eAccessKeyProcessingNormal = 0,
696 eAccessKeyProcessingUp,
697 eAccessKeyProcessingDown
698 };
699
700 /**
701 * Walk EMS to look for access key and execute found access key when aExecute
702 * is true.
703 * If there is registered element for the accesskey given by the key event
704 * and modifier mask then call element.PerformAccesskey(), otherwise call
705 * WalkESMTreeToHandleAccessKey() recursively, on descendant docshells first,
706 * then on the ancestor (with |aBubbledFrom| set to the docshell associated
707 * with |this|), until something matches.
708 *
709 * @param aEvent the keyboard event triggering the acccess key
710 * @param aPresContext the presentation context
711 * @param aAccessCharCodes list of charcode candidates
712 * @param aBubbledFrom is used by an ancestor to avoid calling
713 * WalkESMTreeToHandleAccessKey() on the child the call originally
714 * came from, i.e. this is the child that recursively called us in
715 * its Up phase. The initial caller passes |nullptr| here. This is to
716 * avoid an infinite loop.
717 * @param aAccessKeyState Normal, Down or Up processing phase (see enums
718 * above). The initial event receiver uses 'normal', then 'down' when
719 * processing children and Up when recursively calling its ancestor.
720 * @param aExecute is true, execute an accesskey if it's found. Otherwise,
721 * found accesskey won't be executed.
722 *
723 * @return true if there is a target which aEvent and
724 * aAccessCharCodes match with in this process.
725 * Otherwise, false. I.e., when this returns true and
726 * aExecute is true, a target is executed or focused.
727 * Note that even if this returns false, a target in
728 * remote process may be executed or focused
729 * asynchronously.
730 */
731 bool WalkESMTreeToHandleAccessKey(WidgetKeyboardEvent* aEvent,
732 nsPresContext* aPresContext,
733 nsTArray<uint32_t>& aAccessCharCodes,
734 nsIDocShellTreeItem* aBubbledFrom,
735 ProcessingAccessKeyState aAccessKeyState,
736 bool aExecute);
737
738 /**
739 * Look for access key and execute found access key if aExecute is true in
740 * the instance.
741 *
742 * @return true if there is a target which matches with
743 * aAccessCharCodes and aIsTrustedEvent. Otherwise,
744 * false. I.e., when this returns true and aExecute
745 * is true, a target is executed or focused.
746 */
747 MOZ_CAN_RUN_SCRIPT_BOUNDARY bool LookForAccessKeyAndExecute(
748 nsTArray<uint32_t>& aAccessCharCodes, bool aIsTrustedEvent,
749 bool aIsRepeat, bool aExecute);
750
751 //---------------------------------------------
752 // DocShell Focus Traversal Methods
753 //---------------------------------------------
754
755 dom::Element* GetFocusedElement();
756 bool IsShellVisible(nsIDocShell* aShell);
757
758 // These functions are for mousewheel and pixel scrolling
759
760 class WheelPrefs {
761 public:
762 static WheelPrefs* GetInstance();
763 static void Shutdown();
764
765 /**
766 * ApplyUserPrefsToDelta() overrides the wheel event's delta values with
767 * user prefs.
768 */
769 void ApplyUserPrefsToDelta(WidgetWheelEvent* aEvent);
770
771 /**
772 * Returns whether or not ApplyUserPrefsToDelta() would change the delta
773 * values of an event.
774 */
775 void GetUserPrefsForEvent(const WidgetWheelEvent* aEvent,
776 double* aOutMultiplierX, double* aOutMultiplierY);
777
778 /**
779 * If ApplyUserPrefsToDelta() changed the delta values with customized
780 * prefs, the overflowDelta values would be inflated.
781 * CancelApplyingUserPrefsFromOverflowDelta() cancels the inflation.
782 */
783 void CancelApplyingUserPrefsFromOverflowDelta(WidgetWheelEvent* aEvent);
784
785 /**
786 * Computes the default action for the aEvent with the prefs.
787 */
788 enum Action : uint8_t {
789 ACTION_NONE = 0,
790 ACTION_SCROLL,
791 ACTION_HISTORY,
792 ACTION_ZOOM,
793 // Horizontalized scrolling means treating vertical wheel scrolling as
794 // horizontal scrolling during the process of its default action and
795 // plugins handling scrolling. Note that delta values as the event object
796 // in a DOM event listener won't be affected, and will be still the
797 // original values. For more details, refer to
798 // mozilla::WheelDeltaAdjustmentStrategy::eHorizontalize
799 ACTION_HORIZONTALIZED_SCROLL,
800 ACTION_PINCH_ZOOM,
801 ACTION_LAST = ACTION_PINCH_ZOOM,
802 // Following actions are used only by internal processing. So, cannot
803 // specified by prefs.
804 ACTION_SEND_TO_PLUGIN,
805 };
806 Action ComputeActionFor(const WidgetWheelEvent* aEvent);
807
808 /**
809 * NeedToComputeLineOrPageDelta() returns if the aEvent needs to be
810 * computed the lineOrPageDelta values.
811 */
812 bool NeedToComputeLineOrPageDelta(const WidgetWheelEvent* aEvent);
813
814 /**
815 * IsOverOnePageScrollAllowed*() checks whether wheel scroll amount should
816 * be rounded down to the page width/height (false) or not (true).
817 */
818 bool IsOverOnePageScrollAllowedX(const WidgetWheelEvent* aEvent);
819 bool IsOverOnePageScrollAllowedY(const WidgetWheelEvent* aEvent);
820
821 private:
822 WheelPrefs();
823 ~WheelPrefs();
824
825 static void OnPrefChanged(const char* aPrefName, void* aClosure);
826
827 enum Index {
828 INDEX_DEFAULT = 0,
829 INDEX_ALT,
830 INDEX_CONTROL,
831 INDEX_META,
832 INDEX_SHIFT,
833 COUNT_OF_MULTIPLIERS
834 };
835
836 /**
837 * GetIndexFor() returns the index of the members which should be used for
838 * the aEvent. When only one modifier key of MODIFIER_ALT,
839 * MODIFIER_CONTROL, MODIFIER_META or MODIFIER_SHIFT is pressed, returns the
840 * index for the modifier. Otherwise, this return the default index which
841 * is used at either no modifier key is pressed or two or modifier keys are
842 * pressed.
843 */
844 Index GetIndexFor(const WidgetWheelEvent* aEvent);
845
846 /**
847 * GetPrefNameBase() returns the base pref name for aEvent.
848 * It's decided by GetModifierForPref() which modifier should be used for
849 * the aEvent.
850 *
851 * @param aBasePrefName The result, must be "mousewheel.with_*." or
852 * "mousewheel.default.".
853 */
854 void GetBasePrefName(Index aIndex, nsACString& aBasePrefName);
855
856 void Init(Index aIndex);
857
858 void Reset();
859
860 /**
861 * Retrieve multiplier for aEvent->mDeltaX and aEvent->mDeltaY.
862 *
863 * Note that if the default action is ACTION_HORIZONTALIZED_SCROLL and the
864 * delta values have been adjusted by WheelDeltaHorizontalizer() before this
865 * function is called, this function will swap the X and Y multipliers. By
866 * doing this, multipliers will still apply to the delta values they
867 * originally corresponded to.
868 *
869 * @param aEvent The event which is being handled.
870 * @param aIndex The index of mMultiplierX and mMultiplierY.
871 * Should be result of GetIndexFor(aEvent).
872 * @param aMultiplierForDeltaX Will be set to multiplier for
873 * aEvent->mDeltaX.
874 * @param aMultiplierForDeltaY Will be set to multiplier for
875 * aEvent->mDeltaY.
876 */
877 void GetMultiplierForDeltaXAndY(const WidgetWheelEvent* aEvent,
878 Index aIndex, double* aMultiplierForDeltaX,
879 double* aMultiplierForDeltaY);
880
881 bool mInit[COUNT_OF_MULTIPLIERS];
882 double mMultiplierX[COUNT_OF_MULTIPLIERS];
883 double mMultiplierY[COUNT_OF_MULTIPLIERS];
884 double mMultiplierZ[COUNT_OF_MULTIPLIERS];
885 Action mActions[COUNT_OF_MULTIPLIERS];
886 /**
887 * action values overridden by .override_x pref.
888 * If an .override_x value is -1, same as the
889 * corresponding mActions value.
890 */
891 Action mOverriddenActionsX[COUNT_OF_MULTIPLIERS];
892
893 static WheelPrefs* sInstance;
894 };
895
896 /**
897 * DeltaDirection is used for specifying whether the called method should
898 * handle vertical delta or horizontal delta.
899 * This is clearer than using bool.
900 */
901 enum DeltaDirection { DELTA_DIRECTION_X = 0, DELTA_DIRECTION_Y };
902
903 struct MOZ_STACK_CLASS EventState {
904 bool mDefaultPrevented;
905 bool mDefaultPreventedByContent;
906
907 EventState()
908 : mDefaultPrevented(false), mDefaultPreventedByContent(false) {}
909 };
910
911 /**
912 * SendLineScrollEvent() dispatches a DOMMouseScroll event for the
913 * WidgetWheelEvent. This method shouldn't be called for non-trusted
914 * wheel event because it's not necessary for compatiblity.
915 *
916 * @param aTargetFrame The event target of wheel event.
917 * @param aEvent The original Wheel event.
918 * @param aState The event which should be set to the dispatching
919 * event. This also returns the dispatched event
920 * state.
921 * @param aDelta The delta value of the event.
922 * @param aDeltaDirection The X/Y direction of dispatching event.
923 */
924 MOZ_CAN_RUN_SCRIPT void SendLineScrollEvent(nsIFrame* aTargetFrame,
925 WidgetWheelEvent* aEvent,
926 EventState& aState,
927 int32_t aDelta,
928 DeltaDirection aDeltaDirection);
929
930 /**
931 * SendPixelScrollEvent() dispatches a MozMousePixelScroll event for the
932 * WidgetWheelEvent. This method shouldn't be called for non-trusted
933 * wheel event because it's not necessary for compatiblity.
934 *
935 * @param aTargetFrame The event target of wheel event.
936 * @param aEvent The original Wheel event.
937 * @param aState The event which should be set to the dispatching
938 * event. This also returns the dispatched event
939 * state.
940 * @param aPixelDelta The delta value of the event.
941 * @param aDeltaDirection The X/Y direction of dispatching event.
942 */
943 MOZ_CAN_RUN_SCRIPT void SendPixelScrollEvent(nsIFrame* aTargetFrame,
944 WidgetWheelEvent* aEvent,
945 EventState& aState,
946 int32_t aPixelDelta,
947 DeltaDirection aDeltaDirection);
948
949 /**
950 * ComputeScrollTargetAndMayAdjustWheelEvent() returns the scrollable frame
951 * which should be scrolled.
952 *
953 * @param aTargetFrame The event target of the wheel event.
954 * @param aEvent The handling mouse wheel event.
955 * @param aOptions The options for finding the scroll target.
956 * Callers should use COMPUTE_*.
957 * @return The scrollable frame which should be scrolled.
958 */
959 // These flags are used in ComputeScrollTargetAndMayAdjustWheelEvent().
960 // Callers should use COMPUTE_*.
961 enum {
962 PREFER_MOUSE_WHEEL_TRANSACTION = 0x00000001,
963 PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS = 0x00000002,
964 PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS = 0x00000004,
965 START_FROM_PARENT = 0x00000008,
966 INCLUDE_PLUGIN_AS_TARGET = 0x00000010,
967 // Indicates the wheel scroll event being computed is an auto-dir scroll, so
968 // its delta may be adjusted after being computed.
969 MAY_BE_ADJUSTED_BY_AUTO_DIR = 0x00000020,
970 };
971 enum ComputeScrollTargetOptions {
972 // At computing scroll target for legacy mouse events, we should return
973 // first scrollable element even when it's not scrollable to the direction.
974 COMPUTE_LEGACY_MOUSE_SCROLL_EVENT_TARGET = 0,
975 // Default action prefers the scrolled element immediately before if it's
976 // still under the mouse cursor. Otherwise, it prefers the nearest
977 // scrollable ancestor which will be scrolled actually.
978 COMPUTE_DEFAULT_ACTION_TARGET =
979 (PREFER_MOUSE_WHEEL_TRANSACTION |
980 PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS |
981 PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS),
982 COMPUTE_DEFAULT_ACTION_TARGET_WITH_AUTO_DIR =
983 (COMPUTE_DEFAULT_ACTION_TARGET | MAY_BE_ADJUSTED_BY_AUTO_DIR),
984 // Look for the nearest scrollable ancestor which can be scrollable with
985 // aEvent.
986 COMPUTE_SCROLLABLE_ANCESTOR_ALONG_X_AXIS =
987 (PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS | START_FROM_PARENT),
988 COMPUTE_SCROLLABLE_ANCESTOR_ALONG_Y_AXIS =
989 (PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS | START_FROM_PARENT),
990 COMPUTE_SCROLLABLE_ANCESTOR_ALONG_X_AXIS_WITH_AUTO_DIR =
991 (COMPUTE_SCROLLABLE_ANCESTOR_ALONG_X_AXIS |
992 MAY_BE_ADJUSTED_BY_AUTO_DIR),
993 COMPUTE_SCROLLABLE_ANCESTOR_ALONG_Y_AXIS_WITH_AUTO_DIR =
994 (COMPUTE_SCROLLABLE_ANCESTOR_ALONG_Y_AXIS |
995 MAY_BE_ADJUSTED_BY_AUTO_DIR),
996 };
997
998 // Compute the scroll target.
999 // The delta values in the wheel event may be changed if the event is for
1000 // auto-dir scrolling. For information on auto-dir,
1001 // @see mozilla::WheelDeltaAdjustmentStrategy
1002 ScrollContainerFrame* ComputeScrollTargetAndMayAdjustWheelEvent(
1003 nsIFrame* aTargetFrame, WidgetWheelEvent* aEvent,
1004 ComputeScrollTargetOptions aOptions);
1005
1006 ScrollContainerFrame* ComputeScrollTargetAndMayAdjustWheelEvent(
1007 nsIFrame* aTargetFrame, double aDirectionX, double aDirectionY,
1008 WidgetWheelEvent* aEvent, ComputeScrollTargetOptions aOptions);
1009
1010 ScrollContainerFrame* ComputeScrollTarget(
1011 nsIFrame* aTargetFrame, WidgetWheelEvent* aEvent,
1012 ComputeScrollTargetOptions aOptions) {
1013 MOZ_ASSERT(!(aOptions & MAY_BE_ADJUSTED_BY_AUTO_DIR),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(aOptions & MAY_BE_ADJUSTED_BY_AUTO_DIR))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!(aOptions & MAY_BE_ADJUSTED_BY_AUTO_DIR)))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!(aOptions & MAY_BE_ADJUSTED_BY_AUTO_DIR)"
" (" "aEvent may be modified by auto-dir" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.h"
, 1014); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(aOptions & MAY_BE_ADJUSTED_BY_AUTO_DIR)"
") (" "aEvent may be modified by auto-dir" ")"); do { *((volatile
int*)__null) = 1014; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
13
Taking false branch
14
Loop condition is false. Exiting loop
1014 "aEvent may be modified by auto-dir")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(aOptions & MAY_BE_ADJUSTED_BY_AUTO_DIR))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!(aOptions & MAY_BE_ADJUSTED_BY_AUTO_DIR)))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!(aOptions & MAY_BE_ADJUSTED_BY_AUTO_DIR)"
" (" "aEvent may be modified by auto-dir" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.h"
, 1014); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(aOptions & MAY_BE_ADJUSTED_BY_AUTO_DIR)"
") (" "aEvent may be modified by auto-dir" ")"); do { *((volatile
int*)__null) = 1014; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1015 return ComputeScrollTargetAndMayAdjustWheelEvent(aTargetFrame, aEvent,
15
Passing value via 1st parameter 'aTargetFrame'
16
Calling 'EventStateManager::ComputeScrollTargetAndMayAdjustWheelEvent'
1016 aOptions);
1017 }
1018
1019 ScrollContainerFrame* ComputeScrollTarget(
1020 nsIFrame* aTargetFrame, double aDirectionX, double aDirectionY,
1021 WidgetWheelEvent* aEvent, ComputeScrollTargetOptions aOptions) {
1022 MOZ_ASSERT(!(aOptions & MAY_BE_ADJUSTED_BY_AUTO_DIR),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(aOptions & MAY_BE_ADJUSTED_BY_AUTO_DIR))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!(aOptions & MAY_BE_ADJUSTED_BY_AUTO_DIR)))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!(aOptions & MAY_BE_ADJUSTED_BY_AUTO_DIR)"
" (" "aEvent may be modified by auto-dir" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.h"
, 1023); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(aOptions & MAY_BE_ADJUSTED_BY_AUTO_DIR)"
") (" "aEvent may be modified by auto-dir" ")"); do { *((volatile
int*)__null) = 1023; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
1023 "aEvent may be modified by auto-dir")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(aOptions & MAY_BE_ADJUSTED_BY_AUTO_DIR))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!(aOptions & MAY_BE_ADJUSTED_BY_AUTO_DIR)))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!(aOptions & MAY_BE_ADJUSTED_BY_AUTO_DIR)"
" (" "aEvent may be modified by auto-dir" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.h"
, 1023); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!(aOptions & MAY_BE_ADJUSTED_BY_AUTO_DIR)"
") (" "aEvent may be modified by auto-dir" ")"); do { *((volatile
int*)__null) = 1023; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1024 return ComputeScrollTargetAndMayAdjustWheelEvent(
1025 aTargetFrame, aDirectionX, aDirectionY, aEvent, aOptions);
1026 }
1027
1028 /**
1029 * GetScrollAmount() returns the scroll amount in app uints of one line or
1030 * one page. If the wheel event scrolls a page, returns the page width and
1031 * height. Otherwise, returns line height for both its width and height.
1032 *
1033 * @param aScrollContainerFrame A frame which will be scrolled by the event.
1034 * The result of
1035 * ComputeScrollTargetAndMayAdjustWheelEvent() is
1036 * expected for this value.
1037 * This can be nullptr if there is no scrollable
1038 * frame. Then, this method uses root frame's
1039 * line height or visible area's width and
1040 * height.
1041 */
1042 nsSize GetScrollAmount(nsPresContext* aPresContext, WidgetWheelEvent* aEvent,
1043 ScrollContainerFrame* aScrollContainerFrame);
1044
1045 /**
1046 * DoScrollText() scrolls the scroll container frame for aEvent.
1047 */
1048 void DoScrollText(ScrollContainerFrame* aScrollContainerFrame,
1049 WidgetWheelEvent* aEvent);
1050
1051 void DoScrollHistory(int32_t direction);
1052 void DoScrollZoom(nsIFrame* aTargetFrame, int32_t adjustment);
1053 void ChangeZoom(bool aIncrease);
1054
1055 /**
1056 * DeltaAccumulator class manages delta values for dispatching DOMMouseScroll
1057 * event. If wheel events are caused by pixel scroll only devices or
1058 * the delta values are customized by prefs, this class stores the delta
1059 * values and set lineOrPageDelta values.
1060 */
1061 class DeltaAccumulator {
1062 public:
1063 static DeltaAccumulator* GetInstance() {
1064 if (!sInstance) {
1065 sInstance = new DeltaAccumulator;
1066 }
1067 return sInstance;
1068 }
1069
1070 static void Shutdown() {
1071 delete sInstance;
1072 sInstance = nullptr;
1073 }
1074
1075 bool IsInTransaction() { return mHandlingDeltaMode != UINT32_MAX(4294967295U); }
1076
1077 /**
1078 * InitLineOrPageDelta() stores pixel delta values of WidgetWheelEvents
1079 * which are caused if it's needed. And if the accumulated delta becomes a
1080 * line height, sets lineOrPageDeltaX and lineOrPageDeltaY automatically.
1081 */
1082 void InitLineOrPageDelta(nsIFrame* aTargetFrame, EventStateManager* aESM,
1083 WidgetWheelEvent* aEvent);
1084
1085 /**
1086 * Reset() resets all members.
1087 */
1088 void Reset();
1089
1090 /**
1091 * ComputeScrollAmountForDefaultAction() computes the default action's
1092 * scroll amount in device pixels with mPendingScrollAmount*.
1093 */
1094 nsIntPoint ComputeScrollAmountForDefaultAction(
1095 WidgetWheelEvent* aEvent, const nsIntSize& aScrollAmountInDevPixels);
1096
1097 private:
1098 DeltaAccumulator()
1099 : mX(0.0),
1100 mY(0.0),
1101 mPendingScrollAmountX(0.0),
1102 mPendingScrollAmountY(0.0),
1103 mHandlingDeltaMode(UINT32_MAX(4294967295U)),
1104 mIsNoLineOrPageDeltaDevice(false) {}
1105
1106 double mX;
1107 double mY;
1108
1109 // When default action of a wheel event is scroll but some delta values
1110 // are ignored because the computed amount values are not integer, the
1111 // fractional values are saved by these members.
1112 double mPendingScrollAmountX;
1113 double mPendingScrollAmountY;
1114
1115 TimeStamp mLastTime;
1116
1117 uint32_t mHandlingDeltaMode;
1118 bool mIsNoLineOrPageDeltaDevice;
1119
1120 static DeltaAccumulator* sInstance;
1121 };
1122
1123 // end mousewheel functions
1124
1125 /*
1126 * When a touch gesture is about to start, this function determines what
1127 * kind of gesture interaction we will want to use, based on what is
1128 * underneath the initial touch point.
1129 * Currently it decides between panning (finger scrolling) or dragging
1130 * the target element, as well as the orientation to trigger panning and
1131 * display visual boundary feedback. The decision is stored back in aEvent.
1132 */
1133 void DecideGestureEvent(WidgetGestureNotifyEvent* aEvent,
1134 nsIFrame* targetFrame);
1135
1136 // routines for the d&d gesture tracking state machine
1137 void BeginTrackingDragGesture(nsPresContext* aPresContext,
1138 WidgetMouseEvent* aDownEvent,
1139 nsIFrame* aDownFrame);
1140
1141 void SetGestureDownPoint(WidgetGUIEvent* aEvent);
1142
1143 LayoutDeviceIntPoint GetEventRefPoint(WidgetEvent* aEvent) const;
1144
1145 friend class mozilla::dom::BrowserParent;
1146 void BeginTrackingRemoteDragGesture(nsIContent* aContent,
1147 dom::RemoteDragStartData* aDragStartData);
1148
1149 MOZ_CAN_RUN_SCRIPT
1150 void GenerateDragGesture(nsPresContext* aPresContext,
1151 WidgetInputEvent* aEvent);
1152
1153 /**
1154 * When starting a dnd session, UA must fire a pointercancel event and stop
1155 * firing the subsequent pointer events.
1156 */
1157 MOZ_CAN_RUN_SCRIPT
1158 void MaybeFirePointerCancel(WidgetInputEvent* aEvent);
1159
1160 /**
1161 * Determine which node the drag should be targeted at.
1162 * This is either the node clicked when there is a selection, or, for HTML,
1163 * the element with a draggable property set to true.
1164 *
1165 * aSelectionTarget - target to check for selection
1166 * aDataTransfer - data transfer object that will contain the data to drag
1167 * aAllowEmptyDataTransfer - [out] set to true, if dnd operation can be
1168 * started even if DataTransfer is empty
1169 * aSelection - [out] set to the selection to be dragged
1170 * aTargetNode - [out] the draggable node, or null if there isn't one
1171 * aPrincipal - [out] set to the triggering principal of the drag, or null
1172 * if it's from browser chrome or OS
1173 * aCookieJarSettings - [out] set to the cookieJarSettings of the drag, or
1174 * null if it's from browser chrome or OS.
1175 */
1176 void DetermineDragTargetAndDefaultData(
1177 nsPIDOMWindowOuter* aWindow, nsIContent* aSelectionTarget,
1178 dom::DataTransfer* aDataTransfer, bool* aAllowEmptyDataTransfer,
1179 dom::Selection** aSelection,
1180 dom::RemoteDragStartData** aRemoteDragStartData, nsIContent** aTargetNode,
1181 nsIPrincipal** aPrincipal, nsIContentSecurityPolicy** aCsp,
1182 nsICookieJarSettings** aCookieJarSettings);
1183
1184 /*
1185 * Perform the default handling for the dragstart event and set up a
1186 * drag for aDataTransfer if it contains any data. Returns true if a drag has
1187 * started.
1188 *
1189 * aDragEvent - the dragstart event
1190 * aDataTransfer - the data transfer that holds the data to be dragged
1191 * aAllowEmptyDataTransfer - if true, dnd can be started even if there is no
1192 * data to drag
1193 * aDragTarget - the target of the drag
1194 * aSelection - the selection to be dragged
1195 * aData - information pertaining to a drag started in a child process
1196 * aPrincipal - the triggering principal of the drag, or null if it's from
1197 * browser chrome or OS
1198 * aCookieJarSettings - the cookieJarSettings of the drag. or null if it's
1199 * from browser chrome or OS.
1200 */
1201 MOZ_CAN_RUN_SCRIPT
1202 bool DoDefaultDragStart(
1203 nsPresContext* aPresContext, WidgetDragEvent* aDragEvent,
1204 dom::DataTransfer* aDataTransfer, bool aAllowEmptyDataTransfer,
1205 nsIContent* aDragTarget, dom::Selection* aSelection,
1206 dom::RemoteDragStartData* aDragStartData, nsIPrincipal* aPrincipal,
1207 nsIContentSecurityPolicy* aCsp, nsICookieJarSettings* aCookieJarSettings);
1208
1209 bool IsTrackingDragGesture() const { return mGestureDownContent != nullptr; }
1210 /**
1211 * Set the fields of aEvent to reflect the mouse position and modifier keys
1212 * that were set when the user first pressed the mouse button (stored by
1213 * BeginTrackingDragGesture). aEvent->mWidget must be
1214 * mCurrentTarget->GetNearestWidget().
1215 */
1216 void FillInEventFromGestureDown(WidgetMouseEvent* aEvent);
1217
1218 MOZ_CAN_RUN_SCRIPT
1219 nsresult DoContentCommandEvent(WidgetContentCommandEvent* aEvent);
1220 MOZ_CAN_RUN_SCRIPT
1221 nsresult DoContentCommandInsertTextEvent(WidgetContentCommandEvent* aEvent);
1222 MOZ_CAN_RUN_SCRIPT
1223 nsresult DoContentCommandReplaceTextEvent(WidgetContentCommandEvent* aEvent);
1224 nsresult DoContentCommandScrollEvent(WidgetContentCommandEvent* aEvent);
1225
1226 dom::BrowserParent* GetCrossProcessTarget();
1227 bool IsTargetCrossProcess(WidgetGUIEvent* aEvent);
1228
1229 /**
1230 * DispatchCrossProcessEvent() try to post aEvent to target remote process.
1231 * If you need to check if the event is posted to a remote process, you
1232 * can use aEvent->HasBeenPostedToRemoteProcess().
1233 */
1234 void DispatchCrossProcessEvent(WidgetEvent* aEvent,
1235 dom::BrowserParent* aRemoteTarget,
1236 nsEventStatus* aStatus);
1237 /**
1238 * HandleCrossProcessEvent() may post aEvent to target remote processes.
1239 * When it succeeded to post the event to at least one remote process,
1240 * returns true. Otherwise, including the case not tried to dispatch to
1241 * post the event, returns false.
1242 * If you need to check if the event is posted to at least one remote
1243 * process, you can use aEvent->HasBeenPostedToRemoteProcess().
1244 */
1245 bool HandleCrossProcessEvent(WidgetEvent* aEvent, nsEventStatus* aStatus);
1246
1247 void ReleaseCurrentIMEContentObserver();
1248
1249 MOZ_CAN_RUN_SCRIPT void HandleQueryContentEvent(
1250 WidgetQueryContentEvent* aEvent);
1251
1252 private:
1253 // Removes a node from the :hover / :active chain if needed, notifying if the
1254 // node is not a NAC subtree.
1255 //
1256 // Only meant to be called from ContentRemoved and
1257 // NativeAnonymousContentRemoved.
1258 void RemoveNodeFromChainIfNeeded(ElementState aState,
1259 nsIContent* aContentRemoved, bool aNotify);
1260
1261 bool IsEventOutsideDragThreshold(WidgetInputEvent* aEvent) const;
1262
1263 static inline void DoStateChange(dom::Element* aElement, ElementState aState,
1264 bool aAddState);
1265 static inline void DoStateChange(nsIContent* aContent, ElementState aState,
1266 bool aAddState);
1267 static void UpdateAncestorState(nsIContent* aStartNode,
1268 nsIContent* aStopBefore, ElementState aState,
1269 bool aAddState);
1270
1271 /**
1272 * Update the attribute mLastRefPoint of the mouse event. It should be
1273 * the center of the window while the pointer is locked.
1274 * the same value as mRefPoint while there is no known last ref point.
1275 * the same value as the last known mRefPoint.
1276 */
1277 static void UpdateLastRefPointOfMouseEvent(WidgetMouseEvent* aMouseEvent);
1278
1279 static void ResetPointerToWindowCenterWhilePointerLocked(
1280 WidgetMouseEvent* aMouseEvent);
1281
1282 // Update the last known ref point to the current event's mRefPoint.
1283 static void UpdateLastPointerPosition(WidgetMouseEvent* aMouseEvent);
1284
1285 /**
1286 * Notify target when user has been interaction with some speicific user
1287 * gestures which are eKeyUp, eMouseUp, eTouchEnd.
1288 */
1289 void NotifyTargetUserActivation(WidgetEvent* aEvent,
1290 nsIContent* aTargetContent);
1291
1292 /**
1293 * https://html.spec.whatwg.org/multipage/popover.html#light-dismiss-open-popovers.
1294 */
1295 MOZ_CAN_RUN_SCRIPT void LightDismissOpenPopovers(WidgetEvent* aEvent,
1296 nsIContent* aTargetContent);
1297
1298 already_AddRefed<EventStateManager> ESMFromContentOrThis(
1299 nsIContent* aContent);
1300
1301 struct LastMouseDownInfo {
1302 nsCOMPtr<nsIContent> mLastMouseDownContent;
1303 Maybe<FormControlType> mLastMouseDownInputControlType;
1304 uint32_t mClickCount = 0;
1305 };
1306
1307 LastMouseDownInfo& GetLastMouseDownInfo(int16_t aButton);
1308
1309 // These variables are only relevant if we're the cursor-setting manager.
1310 StyleCursorKind mLockCursor;
1311 bool mHidingCursorWhileTyping = false;
1312
1313 // Last mouse event screen point (in device pixel) when mouse was locked, used
1314 // to restore mouse position after unlocking.
1315 static LayoutDeviceIntPoint sPreLockScreenPoint;
1316
1317 // Stores the mRefPoint of the last synthetic mouse move we dispatched
1318 // to re-center the mouse when we were pointer locked. If this is (-1,-1) it
1319 // means we've not recently dispatched a centering event. We use this to
1320 // detect when we receive the synth event, so we can cancel and not send it
1321 // to content.
1322 static LayoutDeviceIntPoint sSynthCenteringPoint;
1323
1324 WeakFrame mCurrentTarget;
1325 nsCOMPtr<nsIContent> mCurrentTargetContent;
1326 static AutoWeakFrame sLastDragOverFrame;
1327
1328 // Stores the mRefPoint (the offset from the widget's origin in device
1329 // pixels) of the last mouse event.
1330 static LayoutDeviceIntPoint sLastRefPoint;
1331
1332 // member variables for the d&d gesture state machine
1333 LayoutDeviceIntPoint mGestureDownPoint; // screen coordinates
1334 // The content to use as target if we start a d&d (what we drag).
1335 RefPtr<nsIContent> mGestureDownContent;
1336 // The content of the frame where the mouse-down event occurred. It's the same
1337 // as the target in most cases but not always - for example when dragging
1338 // an <area> of an image map this is the image. (bug 289667)
1339 nsCOMPtr<nsIContent> mGestureDownFrameOwner;
1340 // Data associated with a drag started in a content process.
1341 RefPtr<dom::RemoteDragStartData> mGestureDownDragStartData;
1342 // State of keys when the original gesture-down happened
1343 Modifiers mGestureModifiers;
1344 uint16_t mGestureDownButtons;
1345 int16_t mGestureDownButton;
1346
1347 LastMouseDownInfo mLastLeftMouseDownInfo;
1348 LastMouseDownInfo mLastMiddleMouseDownInfo;
1349 LastMouseDownInfo mLastRightMouseDownInfo;
1350
1351 nsCOMPtr<nsIContent> mActiveContent;
1352 nsCOMPtr<nsIContent> mHoverContent;
1353 static nsCOMPtr<nsIContent> sDragOverContent;
1354 nsCOMPtr<nsIContent> mURLTargetContent;
1355 nsCOMPtr<nsINode> mPopoverPointerDownTarget;
1356
1357 nsPresContext* mPresContext; // Not refcnted
1358 RefPtr<dom::Document> mDocument; // Doesn't necessarily need to be owner
1359
1360 RefPtr<IMEContentObserver> mIMEContentObserver;
1361
1362 bool mShouldAlwaysUseLineDeltas : 1;
1363 bool mShouldAlwaysUseLineDeltasInitialized : 1;
1364
1365 bool mGestureDownInTextControl : 1;
1366
1367 bool mInTouchDrag;
1368
1369 bool m_haveShutdown;
1370
1371 RefPtr<OverOutElementsWrapper> mMouseEnterLeaveHelper;
1372 nsRefPtrHashtable<nsUint32HashKey, OverOutElementsWrapper>
1373 mPointersEnterLeaveHelper;
1374
1375 // Array for accesskey support
1376 nsCOMArray<dom::Element> mAccessKeys;
1377
1378 bool ShouldAlwaysUseLineDeltas();
1379
1380 public:
1381 static nsresult UpdateUserActivityTimer(void);
1382
1383 static bool sNormalLMouseEventInProcess;
1384 static int16_t sCurrentMouseBtn;
1385
1386 static EventStateManager* sActiveESM;
1387
1388 static void ClearGlobalActiveContent(EventStateManager* aClearer);
1389
1390 // Functions used for click hold context menus
1391 nsCOMPtr<nsITimer> mClickHoldTimer;
1392 void CreateClickHoldTimer(nsPresContext* aPresContext, nsIFrame* aDownFrame,
1393 WidgetGUIEvent* aMouseDownEvent);
1394 void KillClickHoldTimer();
1395 MOZ_CAN_RUN_SCRIPT_BOUNDARY void FireContextClick();
1396
1397 MOZ_CAN_RUN_SCRIPT static void SetPointerLock(nsIWidget* aWidget,
1398 nsPresContext* aPresContext);
1399 static void sClickHoldCallback(nsITimer* aTimer, void* aESM);
1400};
1401
1402} // namespace mozilla
1403
1404// Click and double-click events need to be handled even for content that
1405// has no frame. This is required for Web compatibility.
1406#define NS_EVENT_NEEDS_FRAME(event)((event)->mMessage != ePointerClick && (event)->
mMessage != eMouseDoubleClick && (event)->mMessage
!= ePointerAuxClick)
\
1407 ((event)->mMessage != ePointerClick && \
1408 (event)->mMessage != eMouseDoubleClick && \
1409 (event)->mMessage != ePointerAuxClick)
1410
1411#endif // mozilla_EventStateManager_h_