Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name EventStateManager.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/events -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/events -resource-dir /usr/lib/llvm-18/lib/clang/18 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /var/lib/jenkins/workspace/firefox-scan-build/dom/events -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/events -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /var/lib/jenkins/workspace/firefox-scan-build/ipc/chromium/src -I /var/lib/jenkins/workspace/firefox-scan-build/docshell/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/html -I /var/lib/jenkins/workspace/firefox-scan-build/dom/storage -I /var/lib/jenkins/workspace/firefox-scan-build/dom/xml -I /var/lib/jenkins/workspace/firefox-scan-build/dom/xul -I /var/lib/jenkins/workspace/firefox-scan-build/js/xpconnect/wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/layout/forms -I /var/lib/jenkins/workspace/firefox-scan-build/layout/generic -I /var/lib/jenkins/workspace/firefox-scan-build/layout/xul -I /var/lib/jenkins/workspace/firefox-scan-build/layout/xul/tree -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -fdeprecated-macro -ferror-limit 19 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-07-30-004816-4182763-1 -x c++ /var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp
1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#include "EventStateManager.h"
8
9#include "mozilla/AsyncEventDispatcher.h"
10#include "mozilla/Attributes.h"
11#include "mozilla/EditorBase.h"
12#include "mozilla/EventDispatcher.h"
13#include "mozilla/EventForwards.h"
14#include "mozilla/Hal.h"
15#include "mozilla/HTMLEditor.h"
16#include "mozilla/IMEStateManager.h"
17#include "mozilla/Likely.h"
18#include "mozilla/FocusModel.h"
19#include "mozilla/MiscEvents.h"
20#include "mozilla/MathAlgorithms.h"
21#include "mozilla/MouseEvents.h"
22#include "mozilla/PointerLockManager.h"
23#include "mozilla/PresShell.h"
24#include "mozilla/ScopeExit.h"
25#include "mozilla/ScrollTypes.h"
26#include "mozilla/TextComposition.h"
27#include "mozilla/TextControlElement.h"
28#include "mozilla/TextEditor.h"
29#include "mozilla/TextEvents.h"
30#include "mozilla/TouchEvents.h"
31#include "mozilla/Telemetry.h"
32#include "mozilla/UniquePtr.h"
33#include "mozilla/dom/BrowserBridgeChild.h"
34#include "mozilla/dom/BrowsingContext.h"
35#include "mozilla/dom/CanonicalBrowsingContext.h"
36#include "mozilla/dom/ContentChild.h"
37#include "mozilla/dom/DOMIntersectionObserver.h"
38#include "mozilla/dom/DragEvent.h"
39#include "mozilla/dom/Event.h"
40#include "mozilla/dom/FrameLoaderBinding.h"
41#include "mozilla/dom/HTMLLabelElement.h"
42#include "mozilla/dom/HTMLInputElement.h"
43#include "mozilla/dom/MouseEventBinding.h"
44#include "mozilla/dom/BrowserChild.h"
45#include "mozilla/dom/PointerEventHandler.h"
46#include "mozilla/dom/UIEvent.h"
47#include "mozilla/dom/UIEventBinding.h"
48#include "mozilla/dom/UserActivation.h"
49#include "mozilla/dom/WheelEventBinding.h"
50#include "mozilla/glean/GleanMetrics.h"
51#include "mozilla/ScrollContainerFrame.h"
52#include "mozilla/StaticPrefs_accessibility.h"
53#include "mozilla/StaticPrefs_browser.h"
54#include "mozilla/StaticPrefs_dom.h"
55#include "mozilla/StaticPrefs_layout.h"
56#include "mozilla/StaticPrefs_mousewheel.h"
57#include "mozilla/StaticPrefs_ui.h"
58#include "mozilla/StaticPrefs_zoom.h"
59
60#include "ContentEventHandler.h"
61#include "IMEContentObserver.h"
62#include "WheelHandlingHelper.h"
63#include "RemoteDragStartData.h"
64
65#include "nsCommandParams.h"
66#include "nsCOMPtr.h"
67#include "nsCopySupport.h"
68#include "nsFocusManager.h"
69#include "nsGenericHTMLElement.h"
70#include "nsIClipboard.h"
71#include "nsIContent.h"
72#include "nsIContentInlines.h"
73#include "mozilla/dom/Document.h"
74#include "nsICookieJarSettings.h"
75#include "nsIFrame.h"
76#include "nsFrameLoaderOwner.h"
77#include "nsIWeakReferenceUtils.h"
78#include "nsIWidget.h"
79#include "nsLiteralString.h"
80#include "nsPresContext.h"
81#include "nsTArray.h"
82#include "nsGkAtoms.h"
83#include "nsIFormControl.h"
84#include "nsComboboxControlFrame.h"
85#include "nsIDOMXULControlElement.h"
86#include "nsNameSpaceManager.h"
87#include "nsIBaseWindow.h"
88#include "nsFrameSelection.h"
89#include "nsPIDOMWindow.h"
90#include "nsPIWindowRoot.h"
91#include "nsIWebNavigation.h"
92#include "nsIDocumentViewer.h"
93#include "nsFrameManager.h"
94#include "nsIBrowserChild.h"
95#include "nsMenuPopupFrame.h"
96
97#include "nsIObserverService.h"
98#include "nsIDocShell.h"
99
100#include "nsSubDocumentFrame.h"
101#include "nsLayoutUtils.h"
102#include "nsIInterfaceRequestorUtils.h"
103#include "nsUnicharUtils.h"
104#include "nsContentUtils.h"
105
106#include "imgIContainer.h"
107#include "nsIProperties.h"
108#include "nsISupportsPrimitives.h"
109
110#include "nsServiceManagerUtils.h"
111#include "nsITimer.h"
112#include "nsFontMetrics.h"
113#include "nsIDragService.h"
114#include "nsIDragSession.h"
115#include "mozilla/dom/DataTransfer.h"
116#include "nsContentAreaDragDrop.h"
117#include "nsTreeBodyFrame.h"
118#include "nsIController.h"
119#include "mozilla/Services.h"
120#include "mozilla/dom/ContentParent.h"
121#include "mozilla/dom/Record.h"
122#include "mozilla/dom/Selection.h"
123
124#include "mozilla/Preferences.h"
125#include "mozilla/LookAndFeel.h"
126#include "mozilla/ProfilerLabels.h"
127#include "Units.h"
128
129#ifdef XP_MACOSX
130# import <ApplicationServices/ApplicationServices.h>
131#endif
132
133namespace mozilla {
134
135using namespace dom;
136
137static const LayoutDeviceIntPoint kInvalidRefPoint =
138 LayoutDeviceIntPoint(-1, -1);
139
140static uint32_t gMouseOrKeyboardEventCounter = 0;
141static nsITimer* gUserInteractionTimer = nullptr;
142static nsITimerCallback* gUserInteractionTimerCallback = nullptr;
143
144static const double kCursorLoadingTimeout = 1000; // ms
145static AutoWeakFrame gLastCursorSourceFrame;
146static TimeStamp gLastCursorUpdateTime;
147static TimeStamp gTypingStartTime;
148static TimeStamp gTypingEndTime;
149static int32_t gTypingInteractionKeyPresses = 0;
150static dom::InteractionData gTypingInteraction = {};
151
152static inline int32_t RoundDown(double aDouble) {
153 return (aDouble > 0) ? static_cast<int32_t>(floor(aDouble))
154 : static_cast<int32_t>(ceil(aDouble));
155}
156
157static bool IsSelectingLink(nsIFrame* aTargetFrame) {
158 if (!aTargetFrame) {
159 return false;
160 }
161 const nsFrameSelection* frameSel = aTargetFrame->GetConstFrameSelection();
162 if (!frameSel || !frameSel->GetDragState()) {
163 return false;
164 }
165
166 if (!nsContentUtils::GetClosestLinkInFlatTree(aTargetFrame->GetContent())) {
167 return false;
168 }
169 return true;
170}
171
172static UniquePtr<WidgetMouseEvent> CreateMouseOrPointerWidgetEvent(
173 WidgetMouseEvent* aMouseEvent, EventMessage aMessage,
174 EventTarget* aRelatedTarget);
175
176/**
177 * Returns the common ancestor for mouseup purpose, given the
178 * current mouseup target and the previous mousedown target.
179 */
180static nsINode* GetCommonAncestorForMouseUp(
181 nsINode* aCurrentMouseUpTarget, nsINode* aLastMouseDownTarget,
182 Maybe<FormControlType>& aLastMouseDownInputControlType) {
183 if (!aCurrentMouseUpTarget || !aLastMouseDownTarget) {
184 return nullptr;
185 }
186
187 if (aCurrentMouseUpTarget == aLastMouseDownTarget) {
188 return aCurrentMouseUpTarget;
189 }
190
191 // Build the chain of parents
192 AutoTArray<nsINode*, 30> parents1;
193 do {
194 parents1.AppendElement(aCurrentMouseUpTarget);
195 aCurrentMouseUpTarget = aCurrentMouseUpTarget->GetFlattenedTreeParentNode();
196 } while (aCurrentMouseUpTarget);
197
198 AutoTArray<nsINode*, 30> parents2;
199 do {
200 parents2.AppendElement(aLastMouseDownTarget);
201 if (aLastMouseDownTarget == parents1.LastElement()) {
202 break;
203 }
204 aLastMouseDownTarget = aLastMouseDownTarget->GetFlattenedTreeParentNode();
205 } while (aLastMouseDownTarget);
206
207 // Find where the parent chain differs
208 uint32_t pos1 = parents1.Length();
209 uint32_t pos2 = parents2.Length();
210 nsINode* parent = nullptr;
211 for (uint32_t len = std::min(pos1, pos2); len > 0; --len) {
212 nsINode* child1 = parents1.ElementAt(--pos1);
213 nsINode* child2 = parents2.ElementAt(--pos2);
214 if (child1 != child2) {
215 break;
216 }
217
218 // If the input control type is different between mouseup and mousedown,
219 // this is not a valid click.
220 if (HTMLInputElement* input = HTMLInputElement::FromNodeOrNull(child1)) {
221 if (aLastMouseDownInputControlType.isSome() &&
222 aLastMouseDownInputControlType.ref() != input->ControlType()) {
223 break;
224 }
225 }
226 parent = child1;
227 }
228
229 return parent;
230}
231
232LazyLogModule sMouseBoundaryLog("MouseBoundaryEvents");
233LazyLogModule sPointerBoundaryLog("PointerBoundaryEvents");
234
235/******************************************************************/
236/* mozilla::UITimerCallback */
237/******************************************************************/
238
239class UITimerCallback final : public nsITimerCallback, public nsINamed {
240 public:
241 UITimerCallback() : mPreviousCount(0) {}
242 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
243 NS_DECL_NSITIMERCALLBACKvirtual nsresult Notify(nsITimer *timer) override; inline void
_ensure_GetName_exists(void) { static_assert(std::is_convertible
<decltype(this), nsINamed*>::value, "nsITimerCallback implementations must also implement nsINamed"
); }
244 NS_DECL_NSINAMEDvirtual nsresult GetName(nsACString& aName) override;
245 private:
246 ~UITimerCallback() = default;
247 uint32_t mPreviousCount;
248};
249
250NS_IMPL_ISUPPORTS(UITimerCallback, nsITimerCallback, nsINamed)MozExternalRefCountType UITimerCallback::AddRef(void) { static_assert
(!std::is_destructible_v<UITimerCallback>, "Reference-counted class "
"UITimerCallback" " should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
250; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("UITimerCallback" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("UITimerCallback" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"UITimerCallback\" != nullptr" " (" "Must specify a name" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"UITimerCallback\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 250; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("UITimerCallback" " not thread-safe"); nsrefcnt
count = ++mRefCnt; NS_LogAddRef((this), (count), ("UITimerCallback"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
UITimerCallback::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 250
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("UITimerCallback" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("UITimerCallback" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"UITimerCallback\" != nullptr" " (" "Must specify a name" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"UITimerCallback\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 250; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("UITimerCallback" " not thread-safe"); const
char* const nametmp = "UITimerCallback"; nsrefcnt count = --
mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count
== 0) { mRefCnt = 1; delete (this); return 0; } return count
; } nsresult UITimerCallback::QueryInterface(const nsIID&
aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<UITimerCallback, nsITimerCallback>, int32_t
( reinterpret_cast<char*>(static_cast<nsITimerCallback
*>((UITimerCallback*)0x1000)) - reinterpret_cast<char*>
((UITimerCallback*)0x1000))}, {&mozilla::detail::kImplementedIID
<UITimerCallback, nsINamed>, int32_t( reinterpret_cast<
char*>(static_cast<nsINamed*>((UITimerCallback*)0x1000
)) - reinterpret_cast<char*>((UITimerCallback*)0x1000))
}, {&mozilla::detail::kImplementedIID<UITimerCallback,
nsISupports>, int32_t(reinterpret_cast<char*>(static_cast
<nsISupports*>( static_cast<nsITimerCallback*>((UITimerCallback
*)0x1000))) - reinterpret_cast<char*>((UITimerCallback*
)0x1000))}, { nullptr, 0 } } ; static_assert((sizeof(table) /
sizeof(table[0])) > 1, "need at least 1 interface"); rv =
NS_TableDrivenQI(static_cast<void*>(this), aIID, aInstancePtr
, table); return rv; }
251
252// If aTimer is nullptr, this method always sends "user-interaction-inactive"
253// notification.
254NS_IMETHODIMPnsresult
255UITimerCallback::Notify(nsITimer* aTimer) {
256 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
257 if (!obs) return NS_ERROR_FAILURE;
258 if ((gMouseOrKeyboardEventCounter == mPreviousCount) || !aTimer) {
259 gMouseOrKeyboardEventCounter = 0;
260 obs->NotifyObservers(nullptr, "user-interaction-inactive", nullptr);
261 if (gUserInteractionTimer) {
262 gUserInteractionTimer->Cancel();
263 NS_RELEASE(gUserInteractionTimer)do { (gUserInteractionTimer)->Release(); (gUserInteractionTimer
) = 0; } while (0)
;
264 }
265 } else {
266 obs->NotifyObservers(nullptr, "user-interaction-active", nullptr);
267 EventStateManager::UpdateUserActivityTimer();
268
269 if (XRE_IsParentProcess()) {
270 hal::BatteryInformation batteryInfo;
271 hal::GetCurrentBatteryInformation(&batteryInfo);
272 glean::power_battery::percentage_when_user_active.AccumulateSingleSample(
273 uint64_t(batteryInfo.level() * 100));
274 }
275 }
276 mPreviousCount = gMouseOrKeyboardEventCounter;
277 return NS_OK;
278}
279
280NS_IMETHODIMPnsresult
281UITimerCallback::GetName(nsACString& aName) {
282 aName.AssignLiteral("UITimerCallback_timer");
283 return NS_OK;
284}
285
286/******************************************************************/
287/* mozilla::OverOutElementsWrapper */
288/******************************************************************/
289
290NS_IMPL_CYCLE_COLLECTION(OverOutElementsWrapper, mDeepestEnterEventTarget,OverOutElementsWrapper::cycleCollection OverOutElementsWrapper
::_cycleCollectorGlobal; void OverOutElementsWrapper::cycleCollection
::Unlink(void* p) { OverOutElementsWrapper* tmp = DowncastCCParticipant
<OverOutElementsWrapper>(p); ImplCycleCollectionUnlink(
tmp->mDeepestEnterEventTarget); ImplCycleCollectionUnlink(
tmp->mDispatchingOverEventTarget); ImplCycleCollectionUnlink
(tmp->mDispatchingOutOrDeepestLeaveEventTarget); (void)tmp
; } nsresult OverOutElementsWrapper::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { OverOutElementsWrapper
* tmp = DowncastCCParticipant<OverOutElementsWrapper>(p
); cb.DescribeRefCountedNode(tmp->mRefCnt.get(), "OverOutElementsWrapper"
); ImplCycleCollectionTraverse(cb, tmp->mDeepestEnterEventTarget
, "mDeepestEnterEventTarget", 0); ImplCycleCollectionTraverse
(cb, tmp->mDispatchingOverEventTarget, "mDispatchingOverEventTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDispatchingOutOrDeepestLeaveEventTarget
, "mDispatchingOutOrDeepestLeaveEventTarget", 0); (void)tmp; return
NS_OK; }
291 mDispatchingOverEventTarget,OverOutElementsWrapper::cycleCollection OverOutElementsWrapper
::_cycleCollectorGlobal; void OverOutElementsWrapper::cycleCollection
::Unlink(void* p) { OverOutElementsWrapper* tmp = DowncastCCParticipant
<OverOutElementsWrapper>(p); ImplCycleCollectionUnlink(
tmp->mDeepestEnterEventTarget); ImplCycleCollectionUnlink(
tmp->mDispatchingOverEventTarget); ImplCycleCollectionUnlink
(tmp->mDispatchingOutOrDeepestLeaveEventTarget); (void)tmp
; } nsresult OverOutElementsWrapper::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { OverOutElementsWrapper
* tmp = DowncastCCParticipant<OverOutElementsWrapper>(p
); cb.DescribeRefCountedNode(tmp->mRefCnt.get(), "OverOutElementsWrapper"
); ImplCycleCollectionTraverse(cb, tmp->mDeepestEnterEventTarget
, "mDeepestEnterEventTarget", 0); ImplCycleCollectionTraverse
(cb, tmp->mDispatchingOverEventTarget, "mDispatchingOverEventTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDispatchingOutOrDeepestLeaveEventTarget
, "mDispatchingOutOrDeepestLeaveEventTarget", 0); (void)tmp; return
NS_OK; }
292 mDispatchingOutOrDeepestLeaveEventTarget)OverOutElementsWrapper::cycleCollection OverOutElementsWrapper
::_cycleCollectorGlobal; void OverOutElementsWrapper::cycleCollection
::Unlink(void* p) { OverOutElementsWrapper* tmp = DowncastCCParticipant
<OverOutElementsWrapper>(p); ImplCycleCollectionUnlink(
tmp->mDeepestEnterEventTarget); ImplCycleCollectionUnlink(
tmp->mDispatchingOverEventTarget); ImplCycleCollectionUnlink
(tmp->mDispatchingOutOrDeepestLeaveEventTarget); (void)tmp
; } nsresult OverOutElementsWrapper::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { OverOutElementsWrapper
* tmp = DowncastCCParticipant<OverOutElementsWrapper>(p
); cb.DescribeRefCountedNode(tmp->mRefCnt.get(), "OverOutElementsWrapper"
); ImplCycleCollectionTraverse(cb, tmp->mDeepestEnterEventTarget
, "mDeepestEnterEventTarget", 0); ImplCycleCollectionTraverse
(cb, tmp->mDispatchingOverEventTarget, "mDispatchingOverEventTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDispatchingOutOrDeepestLeaveEventTarget
, "mDispatchingOutOrDeepestLeaveEventTarget", 0); (void)tmp; return
NS_OK; }
293NS_IMPL_CYCLE_COLLECTING_ADDREF(OverOutElementsWrapper)MozExternalRefCountType OverOutElementsWrapper::AddRef(void) {
static_assert(!std::is_destructible_v<OverOutElementsWrapper
>, "Reference-counted class " "OverOutElementsWrapper" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 293); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
293; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); _mOwningThread.AssertOwnership("OverOutElementsWrapper"
" not thread-safe"); nsISupports* base = OverOutElementsWrapper
::cycleCollection::Upcast(this); nsrefcnt count = mRefCnt.incr
(base); NS_LogAddRef((this), (count), ("OverOutElementsWrapper"
), (uint32_t)(sizeof(*this))); return count; }
294NS_IMPL_CYCLE_COLLECTING_RELEASE(OverOutElementsWrapper)MozExternalRefCountType OverOutElementsWrapper::Release(void)
{ do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 294); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 294
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); _mOwningThread.AssertOwnership("OverOutElementsWrapper"
" not thread-safe"); nsISupports* base = OverOutElementsWrapper
::cycleCollection::Upcast(this); nsrefcnt count = mRefCnt.decr
(base); NS_LogRelease((this), (count), ("OverOutElementsWrapper"
)); return count; } void OverOutElementsWrapper::DeleteCycleCollectable
(void) { delete (this); }
295
296NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(OverOutElementsWrapper)nsresult OverOutElementsWrapper::QueryInterface(const nsIID&
aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 296); MOZ_PretendNoReturn(); } } while (0); nsISupports* foundInterface
; if (TopThreeWordsEquals( aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID), (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID)) && (LowWordEquals(aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID)) || LowWordEquals(aIID, (nsCycleCollectionISupports::COMTypeInfo
<nsCycleCollectionISupports, void>::kIID)))) { if (LowWordEquals
(aIID, (nsXPCOMCycleCollectionParticipant::COMTypeInfo<nsXPCOMCycleCollectionParticipant
, void>::kIID))) { *aInstancePtr = OverOutElementsWrapper::
cycleCollection::GetParticipant(); return NS_OK; } if (LowWordEquals
(aIID, (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID))) { *aInstancePtr = OverOutElementsWrapper::
cycleCollection::Upcast(this); return NS_OK; } foundInterface
= nullptr; } else
297 NS_INTERFACE_MAP_ENTRY(nsISupports)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupports>)) foundInterface = static_cast
<nsISupports*>(this); else
298NS_INTERFACE_MAP_ENDfoundInterface = 0; nsresult status; if (!foundInterface) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(!aIID.Equals((nsISupports::COMTypeInfo<nsISupports
, void>::kIID)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aIID.Equals((nsISupports::COMTypeInfo
<nsISupports, void>::kIID))))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 298); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
")"); do { *((volatile int*)__null) = 298; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); status = NS_NOINTERFACE
; } else { (foundInterface)->AddRef(); status = NS_OK; } *
aInstancePtr = foundInterface; return status; }
299
300already_AddRefed<nsIWidget> OverOutElementsWrapper::GetLastOverWidget() const {
301 nsCOMPtr<nsIWidget> widget = do_QueryReferent(mLastOverWidget);
302 return widget.forget();
303}
304
305void OverOutElementsWrapper::ContentRemoved(nsIContent& aContent) {
306 if (!mDeepestEnterEventTarget) {
307 return;
308 }
309
310 if (!nsContentUtils::ContentIsFlattenedTreeDescendantOf(
311 mDeepestEnterEventTarget, &aContent)) {
312 return;
313 }
314
315 LogModule* const logModule = mType == BoundaryEventType::Mouse
316 ? sMouseBoundaryLog
317 : sPointerBoundaryLog;
318
319 if (!StaticPrefs::
320 dom_events_mouse_pointer_boundary_keep_enter_targets_after_over_target_removed()) {
321 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"over\" event target (%p) is removed"
, mDeepestEnterEventTarget.get()); } } while (0)
322 ("The last \"over\" event target (%p) is removed",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"over\" event target (%p) is removed"
, mDeepestEnterEventTarget.get()); } } while (0)
323 mDeepestEnterEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"over\" event target (%p) is removed"
, mDeepestEnterEventTarget.get()); } } while (0)
;
324 StoreOverEventTargetAndDeepestEnterEventTarget(nullptr);
325 return;
326 }
327
328 if (mDispatchingOverEventTarget &&
329 (mDeepestEnterEventTarget == mDispatchingOverEventTarget ||
330 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
331 mDispatchingOverEventTarget, &aContent))) {
332 if (mDispatchingOverEventTarget ==
333 mDispatchingOutOrDeepestLeaveEventTarget) {
334 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
335 ("The dispatching \"%s\" event target (%p) is removed",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
336 LastOverEventTargetIsOutEventTarget() ? "out" : "leave",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
337 mDispatchingOutOrDeepestLeaveEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
;
338 mDispatchingOutOrDeepestLeaveEventTarget = nullptr;
339 }
340 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"over\" event target (%p) is removed"
, mDispatchingOverEventTarget.get()); } } while (0)
341 ("The dispatching \"over\" event target (%p) is removed",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"over\" event target (%p) is removed"
, mDispatchingOverEventTarget.get()); } } while (0)
342 mDispatchingOverEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"over\" event target (%p) is removed"
, mDispatchingOverEventTarget.get()); } } while (0)
;
343 mDispatchingOverEventTarget = nullptr;
344 }
345 if (mDispatchingOutOrDeepestLeaveEventTarget &&
346 (mDeepestEnterEventTarget == mDispatchingOutOrDeepestLeaveEventTarget ||
347 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
348 mDispatchingOutOrDeepestLeaveEventTarget, &aContent))) {
349 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
350 ("The dispatching \"%s\" event target (%p) is removed",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
351 LastOverEventTargetIsOutEventTarget() ? "out" : "leave",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
352 mDispatchingOutOrDeepestLeaveEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
;
353 mDispatchingOutOrDeepestLeaveEventTarget = nullptr;
354 }
355 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
356 ("The last \"%s\" event target (%p) is removed and now the last "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
357 "deepest enter target becomes %s(%p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
358 LastOverEventTargetIsOutEventTarget() ? "over" : "enter",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
359 mDeepestEnterEventTarget.get(),do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
360 aContent.GetFlattenedTreeParent()do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
361 ? ToString(*aContent.GetFlattenedTreeParent()).c_str()do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
362 : "nullptr",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
363 aContent.GetFlattenedTreeParent()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
;
364 UpdateDeepestEnterEventTarget(aContent.GetFlattenedTreeParent());
365}
366
367void OverOutElementsWrapper::TryToRestorePendingRemovedOverTarget(
368 const WidgetEvent* aEvent) {
369 if (!MaybeHasPendingRemovingOverEventTarget()) {
370 return;
371 }
372
373 LogModule* const logModule = mType == BoundaryEventType::Mouse
374 ? sMouseBoundaryLog
375 : sPointerBoundaryLog;
376
377 // If we receive a mouse event immediately, let's try to restore the last
378 // "over" event target as the following "out" event target. We assume that a
379 // synthesized mousemove or another mouse event is being dispatched at latest
380 // the next animation frame from the removal. However, synthesized mouse move
381 // which is enqueued by ContentRemoved() may not sent to this instance because
382 // the target is considered with the latest layout, so the document of this
383 // instance may be moved somewhere before the next animation frame.
384 // Therefore, we should not restore the last "over" target if we receive an
385 // unexpected event like a keyboard event, a wheel event, etc.
386 if (aEvent->AsMouseEvent()) {
387 // Restore the original "over" event target should be allowed only when it's
388 // reconnected under the last deepest "enter" event target because we need
389 // to dispatch "leave" events later at least on the ancestors which have
390 // never been removed from the tree.
391 // XXX If new ancestor is inserted between mDeepestEnterEventTarget and
392 // mPendingToRemoveLastOverEventTarget, we will dispatch "leave" event even
393 // though we have not dispatched "enter" event on the element. For fixing
394 // this, we need to store the full path of the last "out" event target when
395 // it's removed from the tree. I guess we can be relax for this issue
396 // because this hack is required for web apps which reconnect the target
397 // to the same position immediately.
398 // XXX Should be IsInclusiveFlatTreeDescendantOf()? However, it may
399 // be reconnected into a subtree which is different from where the
400 // last over element was.
401 nsCOMPtr<nsIContent> pendingRemovingOverEventTarget =
402 GetPendingRemovingOverEventTarget();
403 if (pendingRemovingOverEventTarget &&
404 pendingRemovingOverEventTarget->IsInclusiveDescendantOf(
405 mDeepestEnterEventTarget)) {
406 // StoreOverEventTargetAndDeepestEnterEventTarget() always resets
407 // mLastOverWidget. When we restore the pending removing "over" event
408 // target, we need to keep storing the original "over" widget too.
409 nsCOMPtr<nsIWeakReference> widget = std::move(mLastOverWidget);
410 StoreOverEventTargetAndDeepestEnterEventTarget(
411 pendingRemovingOverEventTarget);
412 mLastOverWidget = std::move(widget);
413 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
414 ("The \"over\" event target (%p) is restored",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
415 mDeepestEnterEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
;
416 return;
417 }
418 MOZ_LOG(logModule, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
419 ("Forgetting the last \"over\" event target (%p) because it is not "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
420 "reconnected under the deepest enter event target (%p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
421 mPendingRemovingOverEventTarget.get(),do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
422 mDeepestEnterEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
;
423 } else {
424 MOZ_LOG(logModule, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
425 ("Forgetting the last \"over\" event target (%p) because an "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
426 "unexpected event (%s) is being dispatched, that means that "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
427 "EventStateManager didn't receive a synthesized mousemove which "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
428 "should be dispatched at next animation frame from the removal",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
429 mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage)))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
;
430 }
431
432 // Now, we should not restore mPendingRemovingOverEventTarget to
433 // mDeepestEnterEventTarget anymore since mPendingRemovingOverEventTarget was
434 // moved outside the subtree of mDeepestEnterEventTarget.
435 mPendingRemovingOverEventTarget = nullptr;
436}
437
438void OverOutElementsWrapper::WillDispatchOverAndEnterEvent(
439 nsIContent* aOverEventTarget) {
440 StoreOverEventTargetAndDeepestEnterEventTarget(aOverEventTarget);
441 // Store the first "over" event target we fire and don't refire "over" event
442 // to that element while the first "over" event is still ongoing.
443 mDispatchingOverEventTarget = aOverEventTarget;
444}
445
446void OverOutElementsWrapper::DidDispatchOverAndEnterEvent(
447 nsIContent* aOriginalOverTargetInComposedDoc,
448 nsIWidget* aOverEventTargetWidget) {
449 mDispatchingOverEventTarget = nullptr;
450 mLastOverWidget = do_GetWeakReference(aOverEventTargetWidget);
451
452 // Pointer Events define that once the `pointerover` event target is removed
453 // from the tree, `pointerout` should not be fired on that and the closest
454 // connected ancestor at the target removal should be kept as the deepest
455 // `pointerleave` target. Therefore, we don't need the special handling for
456 // `pointerout` event target if the last `pointerover` target is temporarily
457 // removed from the tree.
458 if (mType == OverOutElementsWrapper::BoundaryEventType::Pointer) {
459 return;
460 }
461
462 // Assume that the caller checks whether aOriginalOverTarget is in the
463 // original document. If we don't enable the strict mouse/pointer event
464 // boundary event dispatching by the pref (see below),
465 // mDeepestEnterEventTarget is set to nullptr when the last "over" target is
466 // removed. Therefore, we cannot check whether aOriginalOverTarget is in the
467 // original document here.
468 if (!aOriginalOverTargetInComposedDoc) {
469 return;
470 }
471 MOZ_ASSERT_IF(mDeepestEnterEventTarget,do { if (mDeepestEnterEventTarget) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mDeepestEnterEventTarget
->GetComposedDoc() == aOriginalOverTargetInComposedDoc->
GetComposedDoc())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget->
GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
")"); do { *((volatile int*)__null) = 473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
472 mDeepestEnterEventTarget->GetComposedDoc() ==do { if (mDeepestEnterEventTarget) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mDeepestEnterEventTarget
->GetComposedDoc() == aOriginalOverTargetInComposedDoc->
GetComposedDoc())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget->
GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
")"); do { *((volatile int*)__null) = 473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
473 aOriginalOverTargetInComposedDoc->GetComposedDoc())do { if (mDeepestEnterEventTarget) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mDeepestEnterEventTarget
->GetComposedDoc() == aOriginalOverTargetInComposedDoc->
GetComposedDoc())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget->
GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
")"); do { *((volatile int*)__null) = 473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
474 // If the "mouseover" event target is removed temporarily while we're
475 // dispatching "mouseover" and "mouseenter" events and the target gets back
476 // under the deepest enter event target, we should restore the "mouseover"
477 // target.
478 if ((!StaticPrefs::
479 dom_events_mouse_pointer_boundary_keep_enter_targets_after_over_target_removed() &&
480 !mDeepestEnterEventTarget) ||
481 (!LastOverEventTargetIsOutEventTarget() && mDeepestEnterEventTarget &&
482 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
483 aOriginalOverTargetInComposedDoc, mDeepestEnterEventTarget))) {
484 StoreOverEventTargetAndDeepestEnterEventTarget(
485 aOriginalOverTargetInComposedDoc);
486 LogModule* const logModule = mType == BoundaryEventType::Mouse
487 ? sMouseBoundaryLog
488 : sPointerBoundaryLog;
489 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
490 ("The \"over\" event target (%p) is restored",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
491 mDeepestEnterEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
;
492 }
493}
494
495void OverOutElementsWrapper::StoreOverEventTargetAndDeepestEnterEventTarget(
496 nsIContent* aOverEventTargetAndDeepestEnterEventTarget) {
497 mDeepestEnterEventTarget = aOverEventTargetAndDeepestEnterEventTarget;
498 mPendingRemovingOverEventTarget = nullptr;
499 mDeepestEnterEventTargetIsOverEventTarget = !!mDeepestEnterEventTarget;
500 mLastOverWidget = nullptr; // Set it after dispatching the "over" event.
501}
502
503void OverOutElementsWrapper::UpdateDeepestEnterEventTarget(
504 nsIContent* aDeepestEnterEventTarget) {
505 if (MOZ_UNLIKELY(mDeepestEnterEventTarget == aDeepestEnterEventTarget)(__builtin_expect(!!(mDeepestEnterEventTarget == aDeepestEnterEventTarget
), 0))
) {
506 return;
507 }
508
509 if (!aDeepestEnterEventTarget) {
510 // If the root element is removed, we don't need to dispatch "leave"
511 // events on any elements. Therefore, we can forget everything.
512 StoreOverEventTargetAndDeepestEnterEventTarget(nullptr);
513 return;
514 }
515
516 if (LastOverEventTargetIsOutEventTarget()) {
517 MOZ_ASSERT(mDeepestEnterEventTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDeepestEnterEventTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("mDeepestEnterEventTarget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 517); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget"
")"); do { *((volatile int*)__null) = 517; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
518 if (mType == BoundaryEventType::Pointer) {
519 // The spec of Pointer Events defines that once the `pointerover` event
520 // target is removed from the tree, `pointerout` should not be fired on
521 // that and the closest connected ancestor at the target removal should be
522 // kept as the deepest `pointerleave` target. All browsers considers the
523 // last `pointerover` event target is removed immediately when it occurs.
524 // Therefore, we don't need the special handling which we do for the
525 // `mouseout` event target below for considering whether we'll dispatch
526 // `pointerout` on the last `pointerover` target.
527 mPendingRemovingOverEventTarget = nullptr;
528 } else {
529 // Now, the `mouseout` event target is removed from the DOM at least
530 // temporarily. Let's keep storing it for restoring it if it's
531 // reconnected into mDeepestEnterEventTarget in a tick because the other
532 // browsers do not treat temporary removal of the last `mouseover` target
533 // keeps storing it as the next `mouseout` event target.
534 MOZ_ASSERT(!mPendingRemovingOverEventTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mPendingRemovingOverEventTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mPendingRemovingOverEventTarget
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!mPendingRemovingOverEventTarget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 534); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mPendingRemovingOverEventTarget"
")"); do { *((volatile int*)__null) = 534; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
535 MOZ_ASSERT(mDeepestEnterEventTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDeepestEnterEventTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("mDeepestEnterEventTarget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 535); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget"
")"); do { *((volatile int*)__null) = 535; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
536 mPendingRemovingOverEventTarget =
537 do_GetWeakReference(mDeepestEnterEventTarget);
538 }
539 } else {
540 MOZ_ASSERT(!mDeepestEnterEventTargetIsOverEventTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDeepestEnterEventTargetIsOverEventTarget)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!mDeepestEnterEventTargetIsOverEventTarget))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!mDeepestEnterEventTargetIsOverEventTarget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 540); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDeepestEnterEventTargetIsOverEventTarget"
")"); do { *((volatile int*)__null) = 540; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
541 // If mDeepestEnterEventTarget is not the last "over" event target, we've
542 // already done the complicated state managing above. Therefore, we only
543 // need to update mDeepestEnterEventTarget in this case.
544 }
545 mDeepestEnterEventTarget = aDeepestEnterEventTarget;
546 mDeepestEnterEventTargetIsOverEventTarget = false;
547 // Do not update mLastOverWidget here because it's required to ignore some
548 // following pointer events which are fired on widget under different top
549 // level widget.
550}
551
552/******************************************************************/
553/* mozilla::EventStateManager */
554/******************************************************************/
555
556static uint32_t sESMInstanceCount = 0;
557
558bool EventStateManager::sNormalLMouseEventInProcess = false;
559int16_t EventStateManager::sCurrentMouseBtn = MouseButton::eNotPressed;
560EventStateManager* EventStateManager::sActiveESM = nullptr;
561EventStateManager* EventStateManager::sCursorSettingManager = nullptr;
562AutoWeakFrame EventStateManager::sLastDragOverFrame = nullptr;
563LayoutDeviceIntPoint EventStateManager::sPreLockScreenPoint =
564 LayoutDeviceIntPoint(0, 0);
565LayoutDeviceIntPoint EventStateManager::sLastRefPoint = kInvalidRefPoint;
566CSSIntPoint EventStateManager::sLastScreenPoint = CSSIntPoint(0, 0);
567LayoutDeviceIntPoint EventStateManager::sSynthCenteringPoint = kInvalidRefPoint;
568CSSIntPoint EventStateManager::sLastClientPoint = CSSIntPoint(0, 0);
569nsCOMPtr<nsIContent> EventStateManager::sDragOverContent = nullptr;
570
571EventStateManager::WheelPrefs* EventStateManager::WheelPrefs::sInstance =
572 nullptr;
573EventStateManager::DeltaAccumulator*
574 EventStateManager::DeltaAccumulator::sInstance = nullptr;
575
576constexpr const StyleCursorKind kInvalidCursorKind =
577 static_cast<StyleCursorKind>(255);
578
579EventStateManager::EventStateManager()
580 : mLockCursor(kInvalidCursorKind),
581 mCurrentTarget(nullptr),
582 // init d&d gesture state machine variables
583 mGestureDownPoint(0, 0),
584 mGestureModifiers(0),
585 mGestureDownButtons(0),
586 mGestureDownButton(0),
587 mPresContext(nullptr),
588 mShouldAlwaysUseLineDeltas(false),
589 mShouldAlwaysUseLineDeltasInitialized(false),
590 mGestureDownInTextControl(false),
591 mInTouchDrag(false),
592 m_haveShutdown(false) {
593 if (sESMInstanceCount == 0) {
594 gUserInteractionTimerCallback = new UITimerCallback();
595 if (gUserInteractionTimerCallback) NS_ADDREF(gUserInteractionTimerCallback)(gUserInteractionTimerCallback)->AddRef();
596 UpdateUserActivityTimer();
597 }
598 ++sESMInstanceCount;
599}
600
601nsresult EventStateManager::UpdateUserActivityTimer() {
602 if (!gUserInteractionTimerCallback) return NS_OK;
603
604 if (!gUserInteractionTimer) {
605 gUserInteractionTimer = NS_NewTimer().take();
606 }
607
608 if (gUserInteractionTimer) {
609 gUserInteractionTimer->InitWithCallback(
610 gUserInteractionTimerCallback,
611 StaticPrefs::dom_events_user_interaction_interval(),
612 nsITimer::TYPE_ONE_SHOT);
613 }
614 return NS_OK;
615}
616
617nsresult EventStateManager::Init() {
618 nsCOMPtr<nsIObserverService> observerService =
619 mozilla::services::GetObserverService();
620 if (!observerService) return NS_ERROR_FAILURE;
621
622 observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown", true);
623
624 return NS_OK;
625}
626
627bool EventStateManager::ShouldAlwaysUseLineDeltas() {
628 if (MOZ_UNLIKELY(!mShouldAlwaysUseLineDeltasInitialized)(__builtin_expect(!!(!mShouldAlwaysUseLineDeltasInitialized),
0))
) {
629 mShouldAlwaysUseLineDeltasInitialized = true;
630 mShouldAlwaysUseLineDeltas =
631 !StaticPrefs::dom_event_wheel_deltaMode_lines_disabled();
632 if (!mShouldAlwaysUseLineDeltas && mDocument) {
633 if (nsIPrincipal* principal =
634 mDocument->GetPrincipalForPrefBasedHacks()) {
635 mShouldAlwaysUseLineDeltas = principal->IsURIInPrefList(
636 "dom.event.wheel-deltaMode-lines.always-enabled");
637 }
638 }
639 }
640 return mShouldAlwaysUseLineDeltas;
641}
642
643EventStateManager::~EventStateManager() {
644 ReleaseCurrentIMEContentObserver();
645
646 if (sActiveESM == this) {
647 sActiveESM = nullptr;
648 }
649
650 if (StaticPrefs::ui_click_hold_context_menus()) {
651 KillClickHoldTimer();
652 }
653
654 if (sCursorSettingManager == this) {
655 sCursorSettingManager = nullptr;
656 }
657
658 --sESMInstanceCount;
659 if (sESMInstanceCount == 0) {
660 WheelTransaction::Shutdown();
661 if (gUserInteractionTimerCallback) {
662 gUserInteractionTimerCallback->Notify(nullptr);
663 NS_RELEASE(gUserInteractionTimerCallback)do { (gUserInteractionTimerCallback)->Release(); (gUserInteractionTimerCallback
) = 0; } while (0)
;
664 }
665 if (gUserInteractionTimer) {
666 gUserInteractionTimer->Cancel();
667 NS_RELEASE(gUserInteractionTimer)do { (gUserInteractionTimer)->Release(); (gUserInteractionTimer
) = 0; } while (0)
;
668 }
669 WheelPrefs::Shutdown();
670 DeltaAccumulator::Shutdown();
671 }
672
673 if (sDragOverContent && sDragOverContent->OwnerDoc() == mDocument) {
674 sDragOverContent = nullptr;
675 }
676
677 if (!m_haveShutdown) {
678 Shutdown();
679
680 // Don't remove from Observer service in Shutdown because Shutdown also
681 // gets called from xpcom shutdown observer. And we don't want to remove
682 // from the service in that case.
683
684 nsCOMPtr<nsIObserverService> observerService =
685 mozilla::services::GetObserverService();
686 if (observerService) {
687 observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown");
688 }
689 }
690}
691
692nsresult EventStateManager::Shutdown() {
693 m_haveShutdown = true;
694 return NS_OK;
695}
696
697NS_IMETHODIMPnsresult
698EventStateManager::Observe(nsISupports* aSubject, const char* aTopic,
699 const char16_t* someData) {
700 if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown")) {
701 Shutdown();
702 }
703
704 return NS_OK;
705}
706
707NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(EventStateManager)nsresult EventStateManager::QueryInterface(const nsIID& aIID
, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 707); MOZ_PretendNoReturn(); } } while (0); nsISupports* foundInterface
; if (TopThreeWordsEquals( aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID), (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID)) && (LowWordEquals(aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID)) || LowWordEquals(aIID, (nsCycleCollectionISupports::COMTypeInfo
<nsCycleCollectionISupports, void>::kIID)))) { if (LowWordEquals
(aIID, (nsXPCOMCycleCollectionParticipant::COMTypeInfo<nsXPCOMCycleCollectionParticipant
, void>::kIID))) { *aInstancePtr = EventStateManager::cycleCollection
::GetParticipant(); return NS_OK; } if (LowWordEquals(aIID, (
nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID))) { *aInstancePtr = EventStateManager::cycleCollection
::Upcast(this); return NS_OK; } foundInterface = nullptr; } else
708 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupports>)) foundInterface = static_cast
<nsISupports*>(static_cast<nsIObserver*>(this)); else
709 NS_INTERFACE_MAP_ENTRY(nsIObserver)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIObserver>)) foundInterface = static_cast
<nsIObserver*>(this); else
710 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupportsWeakReference>)) foundInterface
= static_cast<nsISupportsWeakReference*>(this); else
711NS_INTERFACE_MAP_ENDfoundInterface = 0; nsresult status; if (!foundInterface) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(!aIID.Equals((nsISupports::COMTypeInfo<nsISupports
, void>::kIID)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aIID.Equals((nsISupports::COMTypeInfo
<nsISupports, void>::kIID))))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 711); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
")"); do { *((volatile int*)__null) = 711; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); status = NS_NOINTERFACE
; } else { (foundInterface)->AddRef(); status = NS_OK; } *
aInstancePtr = foundInterface; return status; }
712
713NS_IMPL_CYCLE_COLLECTING_ADDREF(EventStateManager)MozExternalRefCountType EventStateManager::AddRef(void) { static_assert
(!std::is_destructible_v<EventStateManager>, "Reference-counted class "
"EventStateManager" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 713); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
713; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); _mOwningThread.AssertOwnership("EventStateManager"
" not thread-safe"); nsISupports* base = EventStateManager::
cycleCollection::Upcast(this); nsrefcnt count = mRefCnt.incr(
base); NS_LogAddRef((this), (count), ("EventStateManager"), (
uint32_t)(sizeof(*this))); return count; }
714NS_IMPL_CYCLE_COLLECTING_RELEASE(EventStateManager)MozExternalRefCountType EventStateManager::Release(void) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 714); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 714
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); _mOwningThread.AssertOwnership("EventStateManager" " not thread-safe"
); nsISupports* base = EventStateManager::cycleCollection::Upcast
(this); nsrefcnt count = mRefCnt.decr(base); NS_LogRelease((this
), (count), ("EventStateManager")); return count; } void EventStateManager
::DeleteCycleCollectable(void) { delete (this); }
715
716NS_IMPL_CYCLE_COLLECTION_WEAK(EventStateManager, mCurrentTargetContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
717 mGestureDownContent, mGestureDownFrameOwner,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
718 mLastLeftMouseDownInfo.mLastMouseDownContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
719 mLastMiddleMouseDownInfo.mLastMouseDownContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
720 mLastRightMouseDownInfo.mLastMouseDownContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
721 mActiveContent, mHoverContent, mURLTargetContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
722 mPopoverPointerDownTarget, mMouseEnterLeaveHelper,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
723 mPointersEnterLeaveHelper, mDocument,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
724 mIMEContentObserver, mAccessKeys)EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
725
726void EventStateManager::ReleaseCurrentIMEContentObserver() {
727 if (mIMEContentObserver) {
728 mIMEContentObserver->DisconnectFromEventStateManager();
729 }
730 mIMEContentObserver = nullptr;
731}
732
733void EventStateManager::OnStartToObserveContent(
734 IMEContentObserver* aIMEContentObserver) {
735 if (mIMEContentObserver == aIMEContentObserver) {
736 return;
737 }
738 ReleaseCurrentIMEContentObserver();
739 mIMEContentObserver = aIMEContentObserver;
740}
741
742void EventStateManager::OnStopObservingContent(
743 IMEContentObserver* aIMEContentObserver) {
744 aIMEContentObserver->DisconnectFromEventStateManager();
745 NS_ENSURE_TRUE_VOID(mIMEContentObserver == aIMEContentObserver)do { if ((__builtin_expect(!!(!(mIMEContentObserver == aIMEContentObserver
)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mIMEContentObserver == aIMEContentObserver"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 745); return; } } while (false)
;
746 mIMEContentObserver = nullptr;
747}
748
749void EventStateManager::TryToFlushPendingNotificationsToIME() {
750 if (mIMEContentObserver) {
751 mIMEContentObserver->TryToFlushPendingNotifications(true);
752 }
753}
754
755static bool IsMessageMouseUserActivity(EventMessage aMessage) {
756 return aMessage == eMouseMove || aMessage == eMouseUp ||
757 aMessage == eMouseDown || aMessage == ePointerAuxClick ||
758 aMessage == eMouseDoubleClick || aMessage == ePointerClick ||
759 aMessage == eMouseActivate || aMessage == eMouseLongTap;
760}
761
762static bool IsMessageGamepadUserActivity(EventMessage aMessage) {
763 return aMessage == eGamepadButtonDown || aMessage == eGamepadButtonUp ||
764 aMessage == eGamepadAxisMove;
765}
766
767// static
768bool EventStateManager::IsKeyboardEventUserActivity(WidgetEvent* aEvent) {
769 // We ignore things that shouldn't cause popups, but also things that look
770 // like shortcut presses. In some obscure cases these may actually be
771 // website input, but any meaningful website will have other input anyway,
772 // and we can't very well tell whether shortcut input was supposed to be
773 // directed at chrome or the document.
774
775 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
776 // Access keys should be treated as page interaction.
777 if (keyEvent->ModifiersMatchWithAccessKey(AccessKeyType::eContent)) {
778 return true;
779 }
780 if (!keyEvent->CanTreatAsUserInput() || keyEvent->IsControl() ||
781 keyEvent->IsMeta() || keyEvent->IsAlt()) {
782 return false;
783 }
784 // Deal with function keys:
785 switch (keyEvent->mKeyNameIndex) {
786 case KEY_NAME_INDEX_F1:
787 case KEY_NAME_INDEX_F2:
788 case KEY_NAME_INDEX_F3:
789 case KEY_NAME_INDEX_F4:
790 case KEY_NAME_INDEX_F5:
791 case KEY_NAME_INDEX_F6:
792 case KEY_NAME_INDEX_F7:
793 case KEY_NAME_INDEX_F8:
794 case KEY_NAME_INDEX_F9:
795 case KEY_NAME_INDEX_F10:
796 case KEY_NAME_INDEX_F11:
797 case KEY_NAME_INDEX_F12:
798 case KEY_NAME_INDEX_F13:
799 case KEY_NAME_INDEX_F14:
800 case KEY_NAME_INDEX_F15:
801 case KEY_NAME_INDEX_F16:
802 case KEY_NAME_INDEX_F17:
803 case KEY_NAME_INDEX_F18:
804 case KEY_NAME_INDEX_F19:
805 case KEY_NAME_INDEX_F20:
806 case KEY_NAME_INDEX_F21:
807 case KEY_NAME_INDEX_F22:
808 case KEY_NAME_INDEX_F23:
809 case KEY_NAME_INDEX_F24:
810 return false;
811 default:
812 return true;
813 }
814}
815
816static void OnTypingInteractionEnded() {
817 // We don't consider a single keystroke to be typing.
818 if (gTypingInteractionKeyPresses > 1) {
819 gTypingInteraction.mInteractionCount += gTypingInteractionKeyPresses;
820 gTypingInteraction.mInteractionTimeInMilliseconds += static_cast<uint32_t>(
821 std::ceil((gTypingEndTime - gTypingStartTime).ToMilliseconds()));
822 }
823
824 gTypingInteractionKeyPresses = 0;
825 gTypingStartTime = TimeStamp();
826 gTypingEndTime = TimeStamp();
827}
828
829static void HandleKeyUpInteraction(WidgetKeyboardEvent* aKeyEvent) {
830 if (EventStateManager::IsKeyboardEventUserActivity(aKeyEvent)) {
831 TimeStamp now = TimeStamp::Now();
832 if (gTypingEndTime.IsNull()) {
833 gTypingEndTime = now;
834 }
835 TimeDuration delay = now - gTypingEndTime;
836 // Has it been too long since the last keystroke to be considered typing?
837 if (gTypingInteractionKeyPresses > 0 &&
838 delay >
839 TimeDuration::FromMilliseconds(
840 StaticPrefs::browser_places_interactions_typing_timeout_ms())) {
841 OnTypingInteractionEnded();
842 }
843 gTypingInteractionKeyPresses++;
844 if (gTypingStartTime.IsNull()) {
845 gTypingStartTime = now;
846 }
847 gTypingEndTime = now;
848 }
849}
850
851nsresult EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
852 WidgetEvent* aEvent,
853 nsIFrame* aTargetFrame,
854 nsIContent* aTargetContent,
855 nsEventStatus* aStatus,
856 nsIContent* aOverrideClickTarget) {
857 AUTO_PROFILER_LABEL("EventStateManager::PreHandleEvent", DOM)mozilla::AutoProfilerLabel raiiObject857( "EventStateManager::PreHandleEvent"
, nullptr, JS::ProfilingCategoryPair::DOM)
;
858 NS_ENSURE_ARG_POINTER(aStatus)do { if ((__builtin_expect(!!(!(aStatus)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStatus" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 858); return NS_ERROR_INVALID_POINTER; } } while (false)
;
859 NS_ENSURE_ARG(aPresContext)do { if ((__builtin_expect(!!(!(aPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 859); return NS_ERROR_INVALID_ARG; } } while (false)
;
860 if (!aEvent) {
861 NS_ERROR("aEvent is null. This should never happen.")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "aEvent is null. This should never happen."
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 861); MOZ_PretendNoReturn(); } while (0)
;
862 return NS_ERROR_NULL_POINTER;
863 }
864
865 NS_WARNING_ASSERTION(do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
866 !aTargetFrame || !aTargetFrame->GetContent() ||do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
867 aTargetFrame->GetContent() == aTargetContent ||do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
868 aTargetFrame->GetContent()->GetFlattenedTreeParent() ==do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
869 aTargetContent ||do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
870 aTargetFrame->IsGeneratedContentFrame(),do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
871 "aTargetFrame should be related with aTargetContent")do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
;
872#if DEBUG1
873 if (aTargetFrame && aTargetFrame->IsGeneratedContentFrame()) {
874 nsCOMPtr<nsIContent> targetContent;
875 aTargetFrame->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
876 MOZ_ASSERT(aTargetContent == targetContent,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTargetContent == targetContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTargetContent == targetContent
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aTargetContent == targetContent" " (" "Unexpected target for generated content frame!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTargetContent == targetContent"
") (" "Unexpected target for generated content frame!" ")");
do { *((volatile int*)__null) = 877; __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
877 "Unexpected target for generated content frame!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTargetContent == targetContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTargetContent == targetContent
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aTargetContent == targetContent" " (" "Unexpected target for generated content frame!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTargetContent == targetContent"
") (" "Unexpected target for generated content frame!" ")");
do { *((volatile int*)__null) = 877; __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
878 }
879#endif
880
881 mCurrentTarget = aTargetFrame;
882 mCurrentTargetContent = nullptr;
883
884 // Do not take account eMouseEnterIntoWidget/ExitFromWidget so that loading
885 // a page when user is not active doesn't change the state to active.
886 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
887 if (aEvent->IsTrusted() &&
888 ((mouseEvent && mouseEvent->IsReal() &&
889 IsMessageMouseUserActivity(mouseEvent->mMessage)) ||
890 aEvent->mClass == eWheelEventClass ||
891 aEvent->mClass == ePointerEventClass ||
892 aEvent->mClass == eTouchEventClass ||
893 aEvent->mClass == eKeyboardEventClass ||
894 (aEvent->mClass == eDragEventClass && aEvent->mMessage == eDrop) ||
895 IsMessageGamepadUserActivity(aEvent->mMessage))) {
896 if (gMouseOrKeyboardEventCounter == 0) {
897 nsCOMPtr<nsIObserverService> obs =
898 mozilla::services::GetObserverService();
899 if (obs) {
900 obs->NotifyObservers(nullptr, "user-interaction-active", nullptr);
901 UpdateUserActivityTimer();
902 }
903 }
904 ++gMouseOrKeyboardEventCounter;
905
906 nsCOMPtr<nsINode> node = aTargetContent;
907 if (node &&
908 ((aEvent->mMessage == eKeyUp && IsKeyboardEventUserActivity(aEvent)) ||
909 aEvent->mMessage == eMouseUp || aEvent->mMessage == eWheel ||
910 aEvent->mMessage == eTouchEnd || aEvent->mMessage == ePointerUp ||
911 aEvent->mMessage == eDrop)) {
912 Document* doc = node->OwnerDoc();
913 while (doc) {
914 doc->SetUserHasInteracted();
915 doc = nsContentUtils::IsChildOfSameType(doc)
916 ? doc->GetInProcessParentDocument()
917 : nullptr;
918 }
919 }
920 }
921
922 WheelTransaction::OnEvent(aEvent);
923
924 // Focus events don't necessarily need a frame.
925 if (!mCurrentTarget && !aTargetContent) {
926 NS_ERROR("mCurrentTarget and aTargetContent are null")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "mCurrentTarget and aTargetContent are null"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 926); MOZ_PretendNoReturn(); } while (0)
;
927 return NS_ERROR_NULL_POINTER;
928 }
929#ifdef DEBUG1
930 if (aEvent->HasDragEventMessage() && PointerLockManager::IsLocked()) {
931 NS_ASSERTION(PointerLockManager::IsLocked(),do { if (!(PointerLockManager::IsLocked())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Pointer is locked. Drag events should be suppressed when "
"the pointer is locked.", "PointerLockManager::IsLocked()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 933); MOZ_PretendNoReturn(); } } while (0)
932 "Pointer is locked. Drag events should be suppressed when "do { if (!(PointerLockManager::IsLocked())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Pointer is locked. Drag events should be suppressed when "
"the pointer is locked.", "PointerLockManager::IsLocked()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 933); MOZ_PretendNoReturn(); } } while (0)
933 "the pointer is locked.")do { if (!(PointerLockManager::IsLocked())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Pointer is locked. Drag events should be suppressed when "
"the pointer is locked.", "PointerLockManager::IsLocked()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 933); MOZ_PretendNoReturn(); } } while (0)
;
934 }
935#endif
936 // Store last known screenPoint and clientPoint so pointer lock
937 // can use these values as constants.
938 if (aEvent->IsTrusted() &&
939 ((mouseEvent && mouseEvent->IsReal()) ||
940 aEvent->mClass == eWheelEventClass) &&
941 !PointerLockManager::IsLocked()) {
942 // XXX Probably doesn't matter much, but storing these in CSS pixels instead
943 // of device pixels means behavior can be a bit odd if you zoom while
944 // pointer-locked.
945 sLastScreenPoint =
946 Event::GetScreenCoords(aPresContext, aEvent, aEvent->mRefPoint)
947 .extract();
948 sLastClientPoint = Event::GetClientCoords(
949 aPresContext, aEvent, aEvent->mRefPoint, CSSIntPoint(0, 0));
950 }
951
952 *aStatus = nsEventStatus_eIgnore;
953
954 if (aEvent->mClass == eQueryContentEventClass) {
955 HandleQueryContentEvent(aEvent->AsQueryContentEvent());
956 return NS_OK;
957 }
958
959 WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
960 if (touchEvent && mInTouchDrag) {
961 if (touchEvent->mMessage == eTouchMove) {
962 GenerateDragGesture(aPresContext, touchEvent);
963 } else {
964 mInTouchDrag = false;
965 StopTrackingDragGesture(true);
966 }
967 }
968
969 if (mMouseEnterLeaveHelper && aEvent->IsTrusted()) {
970 // When the last `mouseover` event target is removed from the document,
971 // we makes mMouseEnterLeaveHelper update the last deepest `mouseenter`
972 // event target to the removed node parent and mark it as not the following
973 // `mouseout` event target. However, the other browsers may dispatch
974 // `mouseout` on it if it's restored "immediately". Therefore, we use
975 // the next animation frame as the deadline. ContentRemoved() enqueues a
976 // synthesized `mousemove` to dispatch mouse boundary events under the
977 // mouse cursor soon and the synthesized event (or eMouseExitFromWidget if
978 // our window is moved) will reach here at latest the next animation frame.
979 // Therefore, we can use the event as the deadline. If the removed last
980 // `mouseover` target is reconnected before a synthesized mouse event or
981 // a real mouse event, let's restore it as the following `mouseout` event
982 // target. Otherwise, e.g., a keyboard event, let's forget it.
983 mMouseEnterLeaveHelper->TryToRestorePendingRemovedOverTarget(aEvent);
984 }
985
986 static constexpr auto const allowSynthesisForTests = []() -> bool {
987 nsCOMPtr<nsIDragService> dragService =
988 do_GetService("@mozilla.org/widget/dragservice;1");
989 return dragService &&
990 !dragService->GetNeverAllowSessionIsSynthesizedForTests();
991 };
992
993 switch (aEvent->mMessage) {
994 case eContextMenu:
995 if (PointerLockManager::IsLocked()) {
996 return NS_ERROR_DOM_INVALID_STATE_ERR;
997 }
998 break;
999 case eMouseTouchDrag:
1000 mInTouchDrag = true;
1001 BeginTrackingDragGesture(aPresContext, mouseEvent, aTargetFrame);
1002 break;
1003 case eMouseDown: {
1004 switch (mouseEvent->mButton) {
1005 case MouseButton::ePrimary:
1006 BeginTrackingDragGesture(aPresContext, mouseEvent, aTargetFrame);
1007 mLastLeftMouseDownInfo.mClickCount = mouseEvent->mClickCount;
1008 SetClickCount(mouseEvent, aStatus);
1009 sNormalLMouseEventInProcess = true;
1010 break;
1011 case MouseButton::eMiddle:
1012 mLastMiddleMouseDownInfo.mClickCount = mouseEvent->mClickCount;
1013 SetClickCount(mouseEvent, aStatus);
1014 break;
1015 case MouseButton::eSecondary:
1016 mLastRightMouseDownInfo.mClickCount = mouseEvent->mClickCount;
1017 SetClickCount(mouseEvent, aStatus);
1018 break;
1019 }
1020 NotifyTargetUserActivation(aEvent, aTargetContent);
1021 break;
1022 }
1023 case eMouseUp: {
1024 switch (mouseEvent->mButton) {
1025 case MouseButton::ePrimary:
1026 if (StaticPrefs::ui_click_hold_context_menus()) {
1027 KillClickHoldTimer();
1028 }
1029 mInTouchDrag = false;
1030 StopTrackingDragGesture(true);
1031 sNormalLMouseEventInProcess = false;
1032 // then fall through...
1033 [[fallthrough]];
1034 case MouseButton::eSecondary:
1035 case MouseButton::eMiddle:
1036 RefPtr<EventStateManager> esm =
1037 ESMFromContentOrThis(aOverrideClickTarget);
1038 esm->SetClickCount(mouseEvent, aStatus, aOverrideClickTarget);
1039 break;
1040 }
1041 break;
1042 }
1043 case eMouseEnterIntoWidget:
1044 PointerEventHandler::UpdateActivePointerState(mouseEvent, aTargetContent);
1045 // In some cases on e10s eMouseEnterIntoWidget
1046 // event was sent twice into child process of content.
1047 // (From specific widget code (sending is not permanent) and
1048 // from ESM::DispatchMouseOrPointerBoundaryEvent (sending is permanent)).
1049 // IsCrossProcessForwardingStopped() helps to suppress sending accidental
1050 // event from widget code.
1051 aEvent->StopCrossProcessForwarding();
1052 break;
1053 case eMouseExitFromWidget:
1054 // If this is a remote frame, we receive eMouseExitFromWidget from the
1055 // parent the mouse exits our content. Since the parent may update the
1056 // cursor while the mouse is outside our frame, and since PuppetWidget
1057 // caches the current cursor internally, re-entering our content (say from
1058 // over a window edge) wont update the cursor if the cached value and the
1059 // current cursor match. So when the mouse exits a remote frame, clear the
1060 // cached widget cursor so a proper update will occur when the mouse
1061 // re-enters.
1062 if (XRE_IsContentProcess()) {
1063 ClearCachedWidgetCursor(mCurrentTarget);
1064 }
1065
1066 // IsCrossProcessForwardingStopped() helps to suppress double event
1067 // sending into process of content. For more information see comment
1068 // above, at eMouseEnterIntoWidget case.
1069 aEvent->StopCrossProcessForwarding();
1070
1071 // If the event is not a top-level window or puppet widget exit, then it's
1072 // not really an exit --- we may have traversed widget boundaries but
1073 // we're still in our toplevel window or puppet widget.
1074 if (mouseEvent->mExitFrom.value() !=
1075 WidgetMouseEvent::ePlatformTopLevel &&
1076 mouseEvent->mExitFrom.value() != WidgetMouseEvent::ePuppet) {
1077 // Treat it as a synthetic move so we don't generate spurious
1078 // "exit" or "move" events. Any necessary "out" or "over" events
1079 // will be generated by GenerateMouseEnterExit
1080 mouseEvent->mMessage = eMouseMove;
1081 mouseEvent->mReason = WidgetMouseEvent::eSynthesized;
1082 // then fall through...
1083 } else {
1084 MOZ_ASSERT_IF(XRE_IsParentProcess(),do { if (XRE_IsParentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePlatformTopLevel)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1086); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
")"); do { *((volatile int*)__null) = 1086; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1085 mouseEvent->mExitFrom.value() ==do { if (XRE_IsParentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePlatformTopLevel)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1086); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
")"); do { *((volatile int*)__null) = 1086; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1086 WidgetMouseEvent::ePlatformTopLevel)do { if (XRE_IsParentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePlatformTopLevel)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1086); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
")"); do { *((volatile int*)__null) = 1086; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1087 MOZ_ASSERT_IF(XRE_IsContentProcess(), mouseEvent->mExitFrom.value() ==do { if (XRE_IsContentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePuppet)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mouseEvent->mExitFrom.value
() == WidgetMouseEvent::ePuppet))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1088); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
")"); do { *((volatile int*)__null) = 1088; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1088 WidgetMouseEvent::ePuppet)do { if (XRE_IsContentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePuppet)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mouseEvent->mExitFrom.value
() == WidgetMouseEvent::ePuppet))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1088); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
")"); do { *((volatile int*)__null) = 1088; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1089 // We should synthetize corresponding pointer events
1090 GeneratePointerEnterExit(ePointerLeave, mouseEvent);
1091 GenerateMouseEnterExit(mouseEvent);
1092 // This is really an exit and should stop here
1093 aEvent->mMessage = eVoidEvent;
1094 break;
1095 }
1096 [[fallthrough]];
1097 case eMouseMove:
1098 case ePointerDown:
1099 if (aEvent->mMessage == ePointerDown) {
1100 PointerEventHandler::UpdateActivePointerState(mouseEvent,
1101 aTargetContent);
1102 PointerEventHandler::ImplicitlyCapturePointer(aTargetFrame, aEvent);
1103 if (mouseEvent->mInputSource != MouseEvent_Binding::MOZ_SOURCE_TOUCH) {
1104 NotifyTargetUserActivation(aEvent, aTargetContent);
1105 }
1106
1107 LightDismissOpenPopovers(aEvent, aTargetContent);
1108 }
1109 [[fallthrough]];
1110 case ePointerMove: {
1111 if (!mInTouchDrag &&
1112 PointerEventHandler::IsDragAndDropEnabled(*mouseEvent)) {
1113 GenerateDragGesture(aPresContext, mouseEvent);
1114 }
1115 // on the Mac, GenerateDragGesture() may not return until the drag
1116 // has completed and so |aTargetFrame| may have been deleted (moving
1117 // a bookmark, for example). If this is the case, however, we know
1118 // that ClearFrameRefs() has been called and it cleared out
1119 // |mCurrentTarget|. As a result, we should pass |mCurrentTarget|
1120 // into UpdateCursor().
1121 UpdateCursor(aPresContext, mouseEvent, mCurrentTarget, aStatus);
1122
1123 UpdateLastRefPointOfMouseEvent(mouseEvent);
1124 if (PointerLockManager::IsLocked()) {
1125 ResetPointerToWindowCenterWhilePointerLocked(mouseEvent);
1126 }
1127 UpdateLastPointerPosition(mouseEvent);
1128
1129 GenerateMouseEnterExit(mouseEvent);
1130 // Flush pending layout changes, so that later mouse move events
1131 // will go to the right nodes.
1132 FlushLayout(aPresContext);
1133 break;
1134 }
1135 case ePointerUp:
1136 LightDismissOpenPopovers(aEvent, aTargetContent);
1137 GenerateMouseEnterExit(mouseEvent);
1138 break;
1139 case ePointerGotCapture:
1140 GenerateMouseEnterExit(mouseEvent);
1141 break;
1142 case eDragStart:
1143 if (StaticPrefs::ui_click_hold_context_menus()) {
1144 // an external drag gesture event came in, not generated internally
1145 // by Gecko. Make sure we get rid of the click-hold timer.
1146 KillClickHoldTimer();
1147 }
1148 break;
1149 case eDragOver: {
1150 WidgetDragEvent* dragEvent = aEvent->AsDragEvent();
1151 MOZ_ASSERT(dragEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(dragEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(dragEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("dragEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1151); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dragEvent" ")"
); do { *((volatile int*)__null) = 1151; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1152 if (dragEvent->mFlags.mIsSynthesizedForTests &&
1153 allowSynthesisForTests()) {
1154 dragEvent->InitDropEffectForTests();
1155 }
1156 // Send the enter/exit events before eDrop.
1157 GenerateDragDropEnterExit(aPresContext, dragEvent);
1158 break;
1159 }
1160 case eDrop: {
1161 if (aEvent->mFlags.mIsSynthesizedForTests && allowSynthesisForTests()) {
1162 MOZ_ASSERT(aEvent->AsDragEvent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->AsDragEvent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->AsDragEvent()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->AsDragEvent()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1162); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->AsDragEvent()"
")"); do { *((volatile int*)__null) = 1162; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1163 aEvent->AsDragEvent()->InitDropEffectForTests();
1164 }
1165 break;
1166 }
1167 case eKeyPress: {
1168 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
1169 if (keyEvent->ModifiersMatchWithAccessKey(AccessKeyType::eChrome) ||
1170 keyEvent->ModifiersMatchWithAccessKey(AccessKeyType::eContent)) {
1171 // If the eKeyPress event will be sent to a remote process, this
1172 // process needs to wait reply from the remote process for checking if
1173 // preceding eKeyDown event is consumed. If preceding eKeyDown event
1174 // is consumed in the remote process, BrowserChild won't send the event
1175 // back to this process. So, only when this process receives a reply
1176 // eKeyPress event in BrowserParent, we should handle accesskey in this
1177 // process.
1178 if (IsTopLevelRemoteTarget(GetFocusedElement())) {
1179 // However, if there is no accesskey target for the key combination,
1180 // we don't need to wait reply from the remote process. Otherwise,
1181 // Mark the event as waiting reply from remote process and stop
1182 // propagation in this process.
1183 if (CheckIfEventMatchesAccessKey(keyEvent, aPresContext)) {
1184 keyEvent->StopPropagation();
1185 keyEvent->MarkAsWaitingReplyFromRemoteProcess();
1186 }
1187 }
1188 // If the event target is in this process, we can handle accesskey now
1189 // since if preceding eKeyDown event was consumed, eKeyPress event
1190 // won't be dispatched by widget. So, coming eKeyPress event means
1191 // that the preceding eKeyDown event wasn't consumed in this case.
1192 else {
1193 AutoTArray<uint32_t, 10> accessCharCodes;
1194 keyEvent->GetAccessKeyCandidates(accessCharCodes);
1195
1196 if (HandleAccessKey(keyEvent, aPresContext, accessCharCodes)) {
1197 *aStatus = nsEventStatus_eConsumeNoDefault;
1198 }
1199 }
1200 }
1201 }
1202 // then fall through...
1203 [[fallthrough]];
1204 case eKeyDown:
1205 if (aEvent->mMessage == eKeyDown) {
1206 NotifyTargetUserActivation(aEvent, aTargetContent);
1207 }
1208 [[fallthrough]];
1209 case eKeyUp: {
1210 Element* element = GetFocusedElement();
1211 if (element) {
1212 mCurrentTargetContent = element;
1213 }
1214
1215 // NOTE: Don't refer TextComposition::IsComposing() since UI Events
1216 // defines that KeyboardEvent.isComposing is true when it's
1217 // dispatched after compositionstart and compositionend.
1218 // TextComposition::IsComposing() is false even before
1219 // compositionend if there is no composing string.
1220 // And also don't expose other document's composition state.
1221 // A native IME context is typically shared by multiple documents.
1222 // So, don't use GetTextCompositionFor(nsIWidget*) here.
1223 RefPtr<TextComposition> composition =
1224 IMEStateManager::GetTextCompositionFor(aPresContext);
1225 aEvent->AsKeyboardEvent()->mIsComposing = !!composition;
1226
1227 // Widget may need to perform default action for specific keyboard
1228 // event if it's not consumed. In this case, widget has already marked
1229 // the event as "waiting reply from remote process". However, we need
1230 // to reset it if the target (focused content) isn't in a remote process
1231 // because PresShell needs to check if it's marked as so before
1232 // dispatching events into the DOM tree.
1233 if (aEvent->IsWaitingReplyFromRemoteProcess() &&
1234 !aEvent->PropagationStopped() && !IsTopLevelRemoteTarget(element)) {
1235 aEvent->ResetWaitingReplyFromRemoteProcessState();
1236 }
1237 } break;
1238 case eWheel:
1239 case eWheelOperationStart:
1240 case eWheelOperationEnd: {
1241 NS_ASSERTION(aEvent->IsTrusted(),do { if (!(aEvent->IsTrusted())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Untrusted wheel event shouldn't be here", "aEvent->IsTrusted()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1242); MOZ_PretendNoReturn(); } } while (0)
1242 "Untrusted wheel event shouldn't be here")do { if (!(aEvent->IsTrusted())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Untrusted wheel event shouldn't be here", "aEvent->IsTrusted()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1242); MOZ_PretendNoReturn(); } } while (0)
;
1243 using DeltaModeCheckingState = WidgetWheelEvent::DeltaModeCheckingState;
1244
1245 if (Element* element = GetFocusedElement()) {
1246 mCurrentTargetContent = element;
1247 }
1248
1249 if (aEvent->mMessage != eWheel) {
1250 break;
1251 }
1252
1253 WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
1254 WheelPrefs::GetInstance()->ApplyUserPrefsToDelta(wheelEvent);
1255
1256 // If we won't dispatch a DOM event for this event, nothing to do anymore.
1257 if (!wheelEvent->IsAllowedToDispatchDOMEvent()) {
1258 break;
1259 }
1260
1261 if (StaticPrefs::dom_event_wheel_deltaMode_lines_always_disabled()) {
1262 wheelEvent->mDeltaModeCheckingState = DeltaModeCheckingState::Unchecked;
1263 } else if (ShouldAlwaysUseLineDeltas()) {
1264 wheelEvent->mDeltaModeCheckingState = DeltaModeCheckingState::Checked;
1265 } else {
1266 wheelEvent->mDeltaModeCheckingState = DeltaModeCheckingState::Unknown;
1267 }
1268
1269 // Init lineOrPageDelta values for line scroll events for some devices
1270 // on some platforms which might dispatch wheel events which don't
1271 // have lineOrPageDelta values. And also, if delta values are
1272 // customized by prefs, this recomputes them.
1273 DeltaAccumulator::GetInstance()->InitLineOrPageDelta(aTargetFrame, this,
1274 wheelEvent);
1275 } break;
1276 case eSetSelection: {
1277 RefPtr<Element> focuedElement = GetFocusedElement();
1278 IMEStateManager::HandleSelectionEvent(aPresContext, focuedElement,
1279 aEvent->AsSelectionEvent());
1280 break;
1281 }
1282 case eContentCommandCut:
1283 case eContentCommandCopy:
1284 case eContentCommandPaste:
1285 case eContentCommandDelete:
1286 case eContentCommandUndo:
1287 case eContentCommandRedo:
1288 case eContentCommandPasteTransferable:
1289 case eContentCommandLookUpDictionary:
1290 DoContentCommandEvent(aEvent->AsContentCommandEvent());
1291 break;
1292 case eContentCommandInsertText:
1293 DoContentCommandInsertTextEvent(aEvent->AsContentCommandEvent());
1294 break;
1295 case eContentCommandReplaceText:
1296 DoContentCommandReplaceTextEvent(aEvent->AsContentCommandEvent());
1297 break;
1298 case eContentCommandScroll:
1299 DoContentCommandScrollEvent(aEvent->AsContentCommandEvent());
1300 break;
1301 case eCompositionStart:
1302 if (aEvent->IsTrusted()) {
1303 // If the event is trusted event, set the selected text to data of
1304 // composition event.
1305 WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent();
1306 WidgetQueryContentEvent querySelectedTextEvent(
1307 true, eQuerySelectedText, compositionEvent->mWidget);
1308 HandleQueryContentEvent(&querySelectedTextEvent);
1309 if (querySelectedTextEvent.FoundSelection()) {
1310 compositionEvent->mData = querySelectedTextEvent.mReply->DataRef();
1311 }
1312 NS_ASSERTION(querySelectedTextEvent.Succeeded(),do { if (!(querySelectedTextEvent.Succeeded())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Failed to get selected text", "querySelectedTextEvent.Succeeded()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1313); MOZ_PretendNoReturn(); } } while (0)
1313 "Failed to get selected text")do { if (!(querySelectedTextEvent.Succeeded())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Failed to get selected text", "querySelectedTextEvent.Succeeded()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1313); MOZ_PretendNoReturn(); } } while (0)
;
1314 }
1315 break;
1316 case eTouchStart:
1317 SetGestureDownPoint(aEvent->AsTouchEvent());
1318 break;
1319 case eTouchEnd:
1320 NotifyTargetUserActivation(aEvent, aTargetContent);
1321 break;
1322 default:
1323 break;
1324 }
1325 return NS_OK;
1326}
1327
1328// Returns true if this event is likely an user activation for a link or
1329// a link-like button, where modifier keys are likely be used for controlling
1330// where the link is opened.
1331//
1332// The modifiers associated with the user activation is used for controlling
1333// where the `window.open` is opened into.
1334static bool CanReflectModifiersToUserActivation(WidgetInputEvent* aEvent) {
1335 MOZ_ASSERT(aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1336); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1336; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1336 aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1336); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1336; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1337
1338 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
1339 if (keyEvent) {
1340 return keyEvent->CanReflectModifiersToUserActivation();
1341 }
1342
1343 return true;
1344}
1345
1346void EventStateManager::NotifyTargetUserActivation(WidgetEvent* aEvent,
1347 nsIContent* aTargetContent) {
1348 if (!aEvent->IsTrusted()) {
1349 return;
1350 }
1351
1352 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
1353 if (mouseEvent && !mouseEvent->IsReal()) {
1354 return;
1355 }
1356
1357 nsCOMPtr<nsINode> node = aTargetContent;
1358 if (!node) {
1359 return;
1360 }
1361
1362 Document* doc = node->OwnerDoc();
1363 if (!doc) {
1364 return;
1365 }
1366
1367 // Don't gesture activate for key events for keys which are likely
1368 // to be interaction with the browser, OS.
1369 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
1370 if (keyEvent && !keyEvent->CanUserGestureActivateTarget()) {
1371 return;
1372 }
1373
1374 // Touch gestures that end outside the drag target were touches that turned
1375 // into scroll/pan/swipe actions. We don't want to gesture activate on such
1376 // actions, we want to only gesture activate on touches that are taps.
1377 // That is, touches that end in roughly the same place that they started.
1378 if (aEvent->mMessage == eTouchEnd && aEvent->AsTouchEvent() &&
1379 IsEventOutsideDragThreshold(aEvent->AsTouchEvent())) {
1380 return;
1381 }
1382
1383 // Do not treat the click on scrollbar as a user interaction with the web
1384 // content.
1385 if (StaticPrefs::dom_user_activation_ignore_scrollbars() &&
1386 (aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown) &&
1387 aTargetContent->IsInNativeAnonymousSubtree()) {
1388 nsIContent* current = aTargetContent;
1389 do {
1390 nsIContent* root = current->GetClosestNativeAnonymousSubtreeRoot();
1391 if (!root) {
1392 break;
1393 }
1394 if (root->IsXULElement(nsGkAtoms::scrollbar)) {
1395 return;
1396 }
1397 current = root->GetParent();
1398 } while (current);
1399 }
1400
1401 MOZ_ASSERT(aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1402); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1402; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1402 aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1402); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1402; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1403 UserActivation::Modifiers modifiers;
1404 if (WidgetInputEvent* inputEvent = aEvent->AsInputEvent()) {
1405 if (CanReflectModifiersToUserActivation(inputEvent)) {
1406 if (inputEvent->IsShift()) {
1407 modifiers.SetShift();
1408 }
1409 if (inputEvent->IsMeta()) {
1410 modifiers.SetMeta();
1411 }
1412 if (inputEvent->IsControl()) {
1413 modifiers.SetControl();
1414 }
1415 if (inputEvent->IsAlt()) {
1416 modifiers.SetAlt();
1417 }
1418
1419 WidgetMouseEvent* mouseEvent = inputEvent->AsMouseEvent();
1420 if (mouseEvent) {
1421 if (mouseEvent->mButton == MouseButton::eMiddle) {
1422 modifiers.SetMiddleMouse();
1423 }
1424 }
1425 }
1426 }
1427 doc->NotifyUserGestureActivation(modifiers);
1428}
1429
1430// https://html.spec.whatwg.org/multipage/popover.html#popover-light-dismiss
1431void EventStateManager::LightDismissOpenPopovers(WidgetEvent* aEvent,
1432 nsIContent* aTargetContent) {
1433 MOZ_ASSERT(aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == ePointerDown || aEvent->mMessage
== ePointerUp)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
" (" "Light dismiss must be called for pointer up/down only"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1434); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
") (" "Light dismiss must be called for pointer up/down only"
")"); do { *((volatile int*)__null) = 1434; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1434 "Light dismiss must be called for pointer up/down only")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == ePointerDown || aEvent->mMessage
== ePointerUp)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
" (" "Light dismiss must be called for pointer up/down only"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1434); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
") (" "Light dismiss must be called for pointer up/down only"
")"); do { *((volatile int*)__null) = 1434; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1435
1436 if (!StaticPrefs::dom_element_popover_enabled() || !aEvent->IsTrusted() ||
1437 !aTargetContent) {
1438 return;
1439 }
1440
1441 Element* topmostPopover = aTargetContent->OwnerDoc()->GetTopmostAutoPopover();
1442 if (!topmostPopover) {
1443 return;
1444 }
1445
1446 // Pointerdown: set document's popover pointerdown target to the result of
1447 // running topmost clicked popover given target.
1448 if (aEvent->mMessage == ePointerDown) {
1449 mPopoverPointerDownTarget = aTargetContent->GetTopmostClickedPopover();
1450 return;
1451 }
1452
1453 // Pointerup: hide open popovers.
1454 RefPtr<nsINode> ancestor = aTargetContent->GetTopmostClickedPopover();
1455 bool sameTarget = mPopoverPointerDownTarget == ancestor;
1456 mPopoverPointerDownTarget = nullptr;
1457 if (!sameTarget) {
1458 return;
1459 }
1460
1461 if (!ancestor) {
1462 ancestor = aTargetContent->OwnerDoc();
1463 }
1464 RefPtr<Document> doc(ancestor->OwnerDoc());
1465 doc->HideAllPopoversUntil(*ancestor, false, true);
1466}
1467
1468already_AddRefed<EventStateManager> EventStateManager::ESMFromContentOrThis(
1469 nsIContent* aContent) {
1470 if (aContent) {
1471 PresShell* presShell = aContent->OwnerDoc()->GetPresShell();
1472 if (presShell) {
1473 nsPresContext* prescontext = presShell->GetPresContext();
1474 if (prescontext) {
1475 RefPtr<EventStateManager> esm = prescontext->EventStateManager();
1476 if (esm) {
1477 return esm.forget();
1478 }
1479 }
1480 }
1481 }
1482
1483 RefPtr<EventStateManager> esm = this;
1484 return esm.forget();
1485}
1486
1487EventStateManager::LastMouseDownInfo& EventStateManager::GetLastMouseDownInfo(
1488 int16_t aButton) {
1489 switch (aButton) {
1490 case MouseButton::ePrimary:
1491 return mLastLeftMouseDownInfo;
1492 case MouseButton::eMiddle:
1493 return mLastMiddleMouseDownInfo;
1494 case MouseButton::eSecondary:
1495 return mLastRightMouseDownInfo;
1496 default:
1497 MOZ_ASSERT_UNREACHABLE("This button shouldn't use this method")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"This button shouldn't use this method" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1497); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "This button shouldn't use this method"
")"); do { *((volatile int*)__null) = 1497; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1498 return mLastLeftMouseDownInfo;
1499 }
1500}
1501
1502void EventStateManager::HandleQueryContentEvent(
1503 WidgetQueryContentEvent* aEvent) {
1504 switch (aEvent->mMessage) {
1505 case eQuerySelectedText:
1506 case eQueryTextContent:
1507 case eQueryCaretRect:
1508 case eQueryTextRect:
1509 case eQueryEditorRect:
1510 if (!IsTargetCrossProcess(aEvent)) {
1511 break;
1512 }
1513 // Will not be handled locally, remote the event
1514 GetCrossProcessTarget()->HandleQueryContentEvent(*aEvent);
1515 return;
1516 // Following events have not been supported in e10s mode yet.
1517 case eQueryContentState:
1518 case eQuerySelectionAsTransferable:
1519 case eQueryCharacterAtPoint:
1520 case eQueryDOMWidgetHittest:
1521 case eQueryTextRectArray:
1522 break;
1523 default:
1524 return;
1525 }
1526
1527 // If there is an IMEContentObserver, we need to handle QueryContentEvent
1528 // with it.
1529 if (mIMEContentObserver) {
1530 RefPtr<IMEContentObserver> contentObserver = mIMEContentObserver;
1531 contentObserver->HandleQueryContentEvent(aEvent);
1532 return;
1533 }
1534
1535 ContentEventHandler handler(mPresContext);
1536 handler.HandleQueryContentEvent(aEvent);
1537}
1538
1539static AccessKeyType GetAccessKeyTypeFor(nsISupports* aDocShell) {
1540 nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(aDocShell));
1541 if (!treeItem) {
1542 return AccessKeyType::eNone;
1543 }
1544
1545 switch (treeItem->ItemType()) {
1546 case nsIDocShellTreeItem::typeChrome:
1547 return AccessKeyType::eChrome;
1548 case nsIDocShellTreeItem::typeContent:
1549 return AccessKeyType::eContent;
1550 default:
1551 return AccessKeyType::eNone;
1552 }
1553}
1554
1555static bool IsAccessKeyTarget(Element* aElement, nsAString& aKey) {
1556 // Use GetAttr because we want Unicode case=insensitive matching
1557 // XXXbz shouldn't this be case-sensitive, per spec?
1558 nsString contentKey;
1559 if (!aElement || !aElement->GetAttr(nsGkAtoms::accesskey, contentKey) ||
1560 !contentKey.Equals(aKey, nsCaseInsensitiveStringComparator)) {
1561 return false;
1562 }
1563
1564 if (!aElement->IsXULElement()) {
1565 return true;
1566 }
1567
1568 // For XUL we do visibility checks.
1569 nsIFrame* frame = aElement->GetPrimaryFrame();
1570 if (!frame) {
1571 return false;
1572 }
1573
1574 if (frame->IsFocusable()) {
1575 return true;
1576 }
1577
1578 if (!frame->IsVisibleConsideringAncestors()) {
1579 return false;
1580 }
1581
1582 // XUL controls can be activated.
1583 nsCOMPtr<nsIDOMXULControlElement> control = aElement->AsXULControl();
1584 if (control) {
1585 return true;
1586 }
1587
1588 // XUL label elements are never focusable, so we need to check for them
1589 // explicitly before giving up.
1590 if (aElement->IsXULElement(nsGkAtoms::label)) {
1591 return true;
1592 }
1593
1594 return false;
1595}
1596
1597bool EventStateManager::CheckIfEventMatchesAccessKey(
1598 WidgetKeyboardEvent* aEvent, nsPresContext* aPresContext) {
1599 AutoTArray<uint32_t, 10> accessCharCodes;
1600 aEvent->GetAccessKeyCandidates(accessCharCodes);
1601 return WalkESMTreeToHandleAccessKey(aEvent, aPresContext, accessCharCodes,
1602 nullptr, eAccessKeyProcessingNormal,
1603 false);
1604}
1605
1606bool EventStateManager::LookForAccessKeyAndExecute(
1607 nsTArray<uint32_t>& aAccessCharCodes, bool aIsTrustedEvent, bool aIsRepeat,
1608 bool aExecute) {
1609 int32_t count, start = -1;
1610 if (Element* focusedElement = GetFocusedElement()) {
1611 start = mAccessKeys.IndexOf(focusedElement);
1612 if (start == -1 && focusedElement->IsInNativeAnonymousSubtree()) {
1613 start = mAccessKeys.IndexOf(Element::FromNodeOrNull(
1614 focusedElement->GetClosestNativeAnonymousSubtreeRootParentOrHost()));
1615 }
1616 }
1617 RefPtr<Element> element;
1618 int32_t length = mAccessKeys.Count();
1619 for (uint32_t i = 0; i < aAccessCharCodes.Length(); ++i) {
1620 uint32_t ch = aAccessCharCodes[i];
1621 nsAutoString accessKey;
1622 AppendUCS4ToUTF16(ch, accessKey);
1623 for (count = 1; count <= length; ++count) {
1624 // mAccessKeys always stores Element instances.
1625 MOZ_DIAGNOSTIC_ASSERT(length == mAccessKeys.Count())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(length == mAccessKeys.Count())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(length == mAccessKeys.Count(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("length == mAccessKeys.Count()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1625); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "length == mAccessKeys.Count()"
")"); do { *((volatile int*)__null) = 1625; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1626 element = mAccessKeys[(start + count) % length];
1627 if (IsAccessKeyTarget(element, accessKey)) {
1628 if (!aExecute) {
1629 return true;
1630 }
1631 Document* doc = element->OwnerDoc();
1632 const bool shouldActivate = [&] {
1633 if (!StaticPrefs::accessibility_accesskeycausesactivation()) {
1634 return false;
1635 }
1636 if (aIsRepeat && nsContentUtils::IsChromeDoc(doc)) {
1637 return false;
1638 }
1639
1640 // XXXedgar, Bug 1700646, maybe we could use other data structure to
1641 // make searching target with same accesskey easier, and current setup
1642 // could not ensure we cycle the target with tree order.
1643 int32_t j = 0;
1644 while (++j < length) {
1645 Element* el = mAccessKeys[(start + count + j) % length];
1646 if (IsAccessKeyTarget(el, accessKey)) {
1647 return false;
1648 }
1649 }
1650 return true;
1651 }();
1652
1653 // TODO(bug 1641171): This shouldn't be needed if we considered the
1654 // accesskey combination properly.
1655 if (aIsTrustedEvent) {
1656 doc->NotifyUserGestureActivation();
1657 }
1658
1659 auto result =
1660 element->PerformAccesskey(shouldActivate, aIsTrustedEvent);
1661 if (result.isOk()) {
1662 if (result.unwrap() && aIsTrustedEvent) {
1663 // If this is a child process, inform the parent that we want the
1664 // focus, but pass false since we don't want to change the window
1665 // order.
1666 nsIDocShell* docShell = mPresContext->GetDocShell();
1667 nsCOMPtr<nsIBrowserChild> child =
1668 docShell ? docShell->GetBrowserChild() : nullptr;
1669 if (child) {
1670 child->SendRequestFocus(false, CallerType::System);
1671 }
1672 }
1673 return true;
1674 }
1675 }
1676 }
1677 }
1678 return false;
1679}
1680
1681// static
1682void EventStateManager::GetAccessKeyLabelPrefix(Element* aElement,
1683 nsAString& aPrefix) {
1684 aPrefix.Truncate();
1685 nsAutoString separator, modifierText;
1686 nsContentUtils::GetModifierSeparatorText(separator);
1687
1688 AccessKeyType accessKeyType =
1689 GetAccessKeyTypeFor(aElement->OwnerDoc()->GetDocShell());
1690 if (accessKeyType == AccessKeyType::eNone) {
1691 return;
1692 }
1693 Modifiers modifiers = WidgetKeyboardEvent::AccessKeyModifiers(accessKeyType);
1694 if (modifiers == MODIFIER_NONE) {
1695 return;
1696 }
1697
1698 if (modifiers & MODIFIER_CONTROL) {
1699 nsContentUtils::GetControlText(modifierText);
1700 aPrefix.Append(modifierText + separator);
1701 }
1702 if (modifiers & MODIFIER_META) {
1703 nsContentUtils::GetCommandOrWinText(modifierText);
1704 aPrefix.Append(modifierText + separator);
1705 }
1706 if (modifiers & MODIFIER_ALT) {
1707 nsContentUtils::GetAltText(modifierText);
1708 aPrefix.Append(modifierText + separator);
1709 }
1710 if (modifiers & MODIFIER_SHIFT) {
1711 nsContentUtils::GetShiftText(modifierText);
1712 aPrefix.Append(modifierText + separator);
1713 }
1714}
1715
1716struct MOZ_STACK_CLASS AccessKeyInfo {
1717 WidgetKeyboardEvent* event;
1718 nsTArray<uint32_t>& charCodes;
1719
1720 AccessKeyInfo(WidgetKeyboardEvent* aEvent, nsTArray<uint32_t>& aCharCodes)
1721 : event(aEvent), charCodes(aCharCodes) {}
1722};
1723
1724bool EventStateManager::WalkESMTreeToHandleAccessKey(
1725 WidgetKeyboardEvent* aEvent, nsPresContext* aPresContext,
1726 nsTArray<uint32_t>& aAccessCharCodes, nsIDocShellTreeItem* aBubbledFrom,
1727 ProcessingAccessKeyState aAccessKeyState, bool aExecute) {
1728 EnsureDocument(mPresContext);
1729 nsCOMPtr<nsIDocShell> docShell = aPresContext->GetDocShell();
1730 if (NS_WARN_IF(!docShell)NS_warn_if_impl(!docShell, "!docShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1730)
|| NS_WARN_IF(!mDocument)NS_warn_if_impl(!mDocument, "!mDocument", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1730)
) {
1731 return false;
1732 }
1733 AccessKeyType accessKeyType = GetAccessKeyTypeFor(docShell);
1734 if (accessKeyType == AccessKeyType::eNone) {
1735 return false;
1736 }
1737 // Alt or other accesskey modifier is down, we may need to do an accesskey.
1738 if (mAccessKeys.Count() > 0 &&
1739 aEvent->ModifiersMatchWithAccessKey(accessKeyType)) {
1740 // Someone registered an accesskey. Find and activate it.
1741 if (LookForAccessKeyAndExecute(aAccessCharCodes, aEvent->IsTrusted(),
1742 aEvent->mIsRepeat, aExecute)) {
1743 return true;
1744 }
1745 }
1746
1747 int32_t childCount;
1748 docShell->GetInProcessChildCount(&childCount);
1749 for (int32_t counter = 0; counter < childCount; counter++) {
1750 // Not processing the child which bubbles up the handling
1751 nsCOMPtr<nsIDocShellTreeItem> subShellItem;
1752 docShell->GetInProcessChildAt(counter, getter_AddRefs(subShellItem));
1753 if (aAccessKeyState == eAccessKeyProcessingUp &&
1754 subShellItem == aBubbledFrom) {
1755 continue;
1756 }
1757
1758 nsCOMPtr<nsIDocShell> subDS = do_QueryInterface(subShellItem);
1759 if (subDS && IsShellVisible(subDS)) {
1760 // Guarantee subPresShell lifetime while we're handling access key
1761 // since somebody may assume that it won't be deleted before the
1762 // corresponding nsPresContext and EventStateManager.
1763 RefPtr<PresShell> subPresShell = subDS->GetPresShell();
1764
1765 // Docshells need not have a presshell (eg. display:none
1766 // iframes, docshells in transition between documents, etc).
1767 if (!subPresShell) {
1768 // Oh, well. Just move on to the next child
1769 continue;
1770 }
1771
1772 RefPtr<nsPresContext> subPresContext = subPresShell->GetPresContext();
1773
1774 RefPtr<EventStateManager> esm =
1775 static_cast<EventStateManager*>(subPresContext->EventStateManager());
1776
1777 if (esm && esm->WalkESMTreeToHandleAccessKey(
1778 aEvent, subPresContext, aAccessCharCodes, nullptr,
1779 eAccessKeyProcessingDown, aExecute)) {
1780 return true;
1781 }
1782 }
1783 } // if end . checking all sub docshell ends here.
1784
1785 // bubble up the process to the parent docshell if necessary
1786 if (eAccessKeyProcessingDown != aAccessKeyState) {
1787 nsCOMPtr<nsIDocShellTreeItem> parentShellItem;
1788 docShell->GetInProcessParent(getter_AddRefs(parentShellItem));
1789 nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parentShellItem);
1790 if (parentDS) {
1791 // Guarantee parentPresShell lifetime while we're handling access key
1792 // since somebody may assume that it won't be deleted before the
1793 // corresponding nsPresContext and EventStateManager.
1794 RefPtr<PresShell> parentPresShell = parentDS->GetPresShell();
1795 NS_ASSERTION(parentPresShell,do { if (!(parentPresShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Our PresShell exists but the parent's does not?", "parentPresShell"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1796); MOZ_PretendNoReturn(); } } while (0)
1796 "Our PresShell exists but the parent's does not?")do { if (!(parentPresShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Our PresShell exists but the parent's does not?", "parentPresShell"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1796); MOZ_PretendNoReturn(); } } while (0)
;
1797
1798 RefPtr<nsPresContext> parentPresContext =
1799 parentPresShell->GetPresContext();
1800 NS_ASSERTION(parentPresContext, "PresShell without PresContext")do { if (!(parentPresContext)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "PresShell without PresContext", "parentPresContext", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1800); MOZ_PretendNoReturn(); } } while (0)
;
1801
1802 RefPtr<EventStateManager> esm = static_cast<EventStateManager*>(
1803 parentPresContext->EventStateManager());
1804 if (esm && esm->WalkESMTreeToHandleAccessKey(
1805 aEvent, parentPresContext, aAccessCharCodes, docShell,
1806 eAccessKeyProcessingDown, aExecute)) {
1807 return true;
1808 }
1809 }
1810 } // if end. bubble up process
1811
1812 // If the content access key modifier is pressed, try remote children
1813 if (aExecute &&
1814 aEvent->ModifiersMatchWithAccessKey(AccessKeyType::eContent) &&
1815 mDocument && mDocument->GetWindow()) {
1816 // If the focus is currently on a node with a BrowserParent, the key event
1817 // should've gotten forwarded to the child process and HandleAccessKey
1818 // called from there.
1819 if (BrowserParent::GetFrom(GetFocusedElement())) {
1820 // If access key may be only in remote contents, this method won't handle
1821 // access key synchronously. In this case, only reply event should reach
1822 // here.
1823 MOZ_ASSERT(aEvent->IsHandledInRemoteProcess() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->IsHandledInRemoteProcess() || !aEvent->
IsWaitingReplyFromRemoteProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->IsHandledInRemoteProcess
() || !aEvent->IsWaitingReplyFromRemoteProcess()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aEvent->IsHandledInRemoteProcess() || !aEvent->IsWaitingReplyFromRemoteProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1824); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsHandledInRemoteProcess() || !aEvent->IsWaitingReplyFromRemoteProcess()"
")"); do { *((volatile int*)__null) = 1824; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1824 !aEvent->IsWaitingReplyFromRemoteProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->IsHandledInRemoteProcess() || !aEvent->
IsWaitingReplyFromRemoteProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->IsHandledInRemoteProcess
() || !aEvent->IsWaitingReplyFromRemoteProcess()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aEvent->IsHandledInRemoteProcess() || !aEvent->IsWaitingReplyFromRemoteProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1824); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsHandledInRemoteProcess() || !aEvent->IsWaitingReplyFromRemoteProcess()"
")"); do { *((volatile int*)__null) = 1824; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1825 }
1826 // If focus is somewhere else, then we need to check the remote children.
1827 // However, if the event has already been handled in a remote process,
1828 // then, focus is moved from the remote process after posting the event.
1829 // In such case, we shouldn't retry to handle access keys in remote
1830 // processes.
1831 else if (!aEvent->IsHandledInRemoteProcess()) {
1832 AccessKeyInfo accessKeyInfo(aEvent, aAccessCharCodes);
1833 nsContentUtils::CallOnAllRemoteChildren(
1834 mDocument->GetWindow(),
1835 [&accessKeyInfo](BrowserParent* aBrowserParent) -> CallState {
1836 // Only forward accesskeys for the active tab.
1837 if (aBrowserParent->GetDocShellIsActive()) {
1838 // Even if there is no target for the accesskey in this process,
1839 // the event may match with a content accesskey. If so, the
1840 // keyboard event should be handled with reply event for
1841 // preventing double action. (e.g., Alt+Shift+F on Windows may
1842 // focus a content in remote and open "File" menu.)
1843 accessKeyInfo.event->StopPropagation();
1844 accessKeyInfo.event->MarkAsWaitingReplyFromRemoteProcess();
1845 aBrowserParent->HandleAccessKey(*accessKeyInfo.event,
1846 accessKeyInfo.charCodes);
1847 return CallState::Stop;
1848 }
1849
1850 return CallState::Continue;
1851 });
1852 }
1853 }
1854
1855 return false;
1856} // end of HandleAccessKey
1857
1858static BrowserParent* GetBrowserParentAncestor(BrowserParent* aBrowserParent) {
1859 MOZ_ASSERT(aBrowserParent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aBrowserParent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aBrowserParent))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aBrowserParent"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1859); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aBrowserParent"
")"); do { *((volatile int*)__null) = 1859; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1860
1861 BrowserBridgeParent* bbp = aBrowserParent->GetBrowserBridgeParent();
1862 if (!bbp) {
1863 return nullptr;
1864 }
1865
1866 return bbp->Manager();
1867}
1868
1869static void DispatchCrossProcessMouseExitEvents(WidgetMouseEvent* aMouseEvent,
1870 BrowserParent* aRemoteTarget,
1871 BrowserParent* aStopAncestor,
1872 bool aIsReallyExit) {
1873 MOZ_ASSERT(aMouseEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseEvent))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aMouseEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1873); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseEvent"
")"); do { *((volatile int*)__null) = 1873; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1874 MOZ_ASSERT(aRemoteTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRemoteTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aRemoteTarget))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aRemoteTarget",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1874); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRemoteTarget"
")"); do { *((volatile int*)__null) = 1874; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1875 MOZ_ASSERT(aRemoteTarget != aStopAncestor)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRemoteTarget != aStopAncestor)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aRemoteTarget != aStopAncestor
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aRemoteTarget != aStopAncestor", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1875); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRemoteTarget != aStopAncestor"
")"); do { *((volatile int*)__null) = 1875; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1876 MOZ_ASSERT_IF(aStopAncestor, nsContentUtils::GetCommonBrowserParentAncestor(do { if (aStopAncestor) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(nsContentUtils::GetCommonBrowserParentAncestor
( aRemoteTarget, aStopAncestor))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nsContentUtils::GetCommonBrowserParentAncestor
( aRemoteTarget, aStopAncestor)))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("nsContentUtils::GetCommonBrowserParentAncestor( aRemoteTarget, aStopAncestor)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::GetCommonBrowserParentAncestor( aRemoteTarget, aStopAncestor)"
")"); do { *((volatile int*)__null) = 1877; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1877 aRemoteTarget, aStopAncestor))do { if (aStopAncestor) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(nsContentUtils::GetCommonBrowserParentAncestor
( aRemoteTarget, aStopAncestor))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nsContentUtils::GetCommonBrowserParentAncestor
( aRemoteTarget, aStopAncestor)))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("nsContentUtils::GetCommonBrowserParentAncestor( aRemoteTarget, aStopAncestor)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::GetCommonBrowserParentAncestor( aRemoteTarget, aStopAncestor)"
")"); do { *((volatile int*)__null) = 1877; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1878
1879 while (aRemoteTarget != aStopAncestor) {
1880 UniquePtr<WidgetMouseEvent> mouseExitEvent =
1881 CreateMouseOrPointerWidgetEvent(aMouseEvent, eMouseExitFromWidget,
1882 aMouseEvent->mRelatedTarget);
1883 mouseExitEvent->mExitFrom =
1884 Some(aIsReallyExit ? WidgetMouseEvent::ePuppet
1885 : WidgetMouseEvent::ePuppetParentToPuppetChild);
1886 aRemoteTarget->SendRealMouseEvent(*mouseExitEvent);
1887
1888 aRemoteTarget = GetBrowserParentAncestor(aRemoteTarget);
1889 }
1890}
1891
1892void EventStateManager::DispatchCrossProcessEvent(WidgetEvent* aEvent,
1893 BrowserParent* aRemoteTarget,
1894 nsEventStatus* aStatus) {
1895 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1895); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 1895; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1896 MOZ_ASSERT(aRemoteTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRemoteTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aRemoteTarget))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aRemoteTarget",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1896); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRemoteTarget"
")"); do { *((volatile int*)__null) = 1896; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1897 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1897); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 1897; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1898
1899 BrowserParent* remote = aRemoteTarget;
1900
1901 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
1902 bool isContextMenuKey = mouseEvent && mouseEvent->IsContextMenuKeyEvent();
1903 if (aEvent->mClass == eKeyboardEventClass || isContextMenuKey) {
1904 // APZ attaches a LayersId to hit-testable events, for keyboard events,
1905 // we use focus.
1906 BrowserParent* preciseRemote = BrowserParent::GetFocused();
1907 if (preciseRemote) {
1908 remote = preciseRemote;
1909 }
1910 // else there is a race between layout and focus tracking,
1911 // so fall back to delivering the event to the topmost child process.
1912 } else if (aEvent->mLayersId.IsValid()) {
1913 BrowserParent* preciseRemote =
1914 BrowserParent::GetBrowserParentFromLayersId(aEvent->mLayersId);
1915 if (preciseRemote) {
1916 remote = preciseRemote;
1917 }
1918 // else there is a race between APZ and the LayersId to BrowserParent
1919 // mapping, so fall back to delivering the event to the topmost child
1920 // process.
1921 }
1922
1923 MOZ_ASSERT(aEvent->mMessage != ePointerClick)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage != ePointerClick)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage != ePointerClick
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aEvent->mMessage != ePointerClick", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1923); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage != ePointerClick"
")"); do { *((volatile int*)__null) = 1923; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1924 MOZ_ASSERT(aEvent->mMessage != ePointerAuxClick)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage != ePointerAuxClick)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage != ePointerAuxClick))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage != ePointerAuxClick"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1924); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage != ePointerAuxClick"
")"); do { *((volatile int*)__null) = 1924; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1925
1926 // SendReal* will transform the coordinate to the child process coordinate
1927 // space. So restore the coordinate after the event has been dispatched to the
1928 // child process to avoid using the transformed coordinate afterward.
1929 AutoRestore<LayoutDeviceIntPoint> restore(aEvent->mRefPoint);
1930 switch (aEvent->mClass) {
1931 case ePointerEventClass:
1932 MOZ_ASSERT(aEvent->mMessage == eContextMenu)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eContextMenu)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eContextMenu
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aEvent->mMessage == eContextMenu", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1932); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eContextMenu"
")"); do { *((volatile int*)__null) = 1932; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1933 [[fallthrough]];
1934 case eMouseEventClass: {
1935 BrowserParent* oldRemote = BrowserParent::GetLastMouseRemoteTarget();
1936
1937 // If this is a eMouseExitFromWidget event, need to redirect the event to
1938 // the last remote and and notify all its ancestors about the exit, if
1939 // any.
1940 if (mouseEvent->mMessage == eMouseExitFromWidget) {
1941 MOZ_ASSERT(mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mouseEvent->mExitFrom.value() == WidgetMouseEvent
::ePuppet)>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(mouseEvent->mExitFrom.value() ==
WidgetMouseEvent::ePuppet))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1941); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
")"); do { *((volatile int*)__null) = 1941; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1942 MOZ_ASSERT(mouseEvent->mReason == WidgetMouseEvent::eReal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mouseEvent->mReason == WidgetMouseEvent::eReal)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mouseEvent->mReason == WidgetMouseEvent::eReal)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("mouseEvent->mReason == WidgetMouseEvent::eReal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1942); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mReason == WidgetMouseEvent::eReal"
")"); do { *((volatile int*)__null) = 1942; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1943 MOZ_ASSERT(!mouseEvent->mLayersId.IsValid())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mouseEvent->mLayersId.IsValid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mouseEvent->mLayersId.IsValid
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mouseEvent->mLayersId.IsValid()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1943); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mouseEvent->mLayersId.IsValid()"
")"); do { *((volatile int*)__null) = 1943; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1944 MOZ_ASSERT(remote->GetBrowserHost())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(remote->GetBrowserHost())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(remote->GetBrowserHost())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("remote->GetBrowserHost()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1944); AnnotateMozCrashReason("MOZ_ASSERT" "(" "remote->GetBrowserHost()"
")"); do { *((volatile int*)__null) = 1944; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1945
1946 if (oldRemote && oldRemote != remote) {
1947 Unused << NS_WARN_IF(nsContentUtils::GetCommonBrowserParentAncestor(NS_warn_if_impl(nsContentUtils::GetCommonBrowserParentAncestor
( remote, oldRemote) != remote, "nsContentUtils::GetCommonBrowserParentAncestor( remote, oldRemote) != remote"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1948)
1948 remote, oldRemote) != remote)NS_warn_if_impl(nsContentUtils::GetCommonBrowserParentAncestor
( remote, oldRemote) != remote, "nsContentUtils::GetCommonBrowserParentAncestor( remote, oldRemote) != remote"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1948)
;
1949 remote = oldRemote;
1950 }
1951
1952 DispatchCrossProcessMouseExitEvents(mouseEvent, remote, nullptr, true);
1953 return;
1954 }
1955
1956 if (BrowserParent* pointerLockedRemote =
1957 PointerLockManager::GetLockedRemoteTarget()) {
1958 remote = pointerLockedRemote;
1959 } else if (BrowserParent* pointerCapturedRemote =
1960 PointerEventHandler::GetPointerCapturingRemoteTarget(
1961 mouseEvent->pointerId)) {
1962 remote = pointerCapturedRemote;
1963 } else if (BrowserParent* capturingRemote =
1964 PresShell::GetCapturingRemoteTarget()) {
1965 remote = capturingRemote;
1966 }
1967
1968 // If a mouse is over a remote target A, and then moves to
1969 // remote target B, we'd deliver the event directly to remote target B
1970 // after the moving, A would never get notified that the mouse left.
1971 // So we generate a exit event to notify A after the move.
1972 // XXXedgar, if the synthesized mouse events could deliver to the correct
1973 // process directly (see
1974 // https://bugzilla.mozilla.org/show_bug.cgi?id=1549355), we probably
1975 // don't need to check mReason then.
1976 if (mouseEvent->mReason == WidgetMouseEvent::eReal &&
1977 remote != oldRemote) {
1978 MOZ_ASSERT(mouseEvent->mMessage != eMouseExitFromWidget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mouseEvent->mMessage != eMouseExitFromWidget)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mouseEvent->mMessage != eMouseExitFromWidget))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mouseEvent->mMessage != eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1978); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mMessage != eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 1978; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1979 if (oldRemote) {
1980 BrowserParent* commonAncestor =
1981 nsContentUtils::GetCommonBrowserParentAncestor(remote, oldRemote);
1982 if (commonAncestor == oldRemote) {
1983 // Mouse moves to the inner OOP frame, it is not a really exit.
1984 DispatchCrossProcessMouseExitEvents(
1985 mouseEvent, GetBrowserParentAncestor(remote),
1986 GetBrowserParentAncestor(commonAncestor), false);
1987 } else if (commonAncestor == remote) {
1988 // Mouse moves to the outer OOP frame, it is a really exit.
1989 DispatchCrossProcessMouseExitEvents(mouseEvent, oldRemote,
1990 commonAncestor, true);
1991 } else {
1992 // Mouse moves to OOP frame in other subtree, it is a really exit,
1993 // need to notify all its ancestors before common ancestor about the
1994 // exit.
1995 DispatchCrossProcessMouseExitEvents(mouseEvent, oldRemote,
1996 commonAncestor, true);
1997 if (commonAncestor) {
1998 UniquePtr<WidgetMouseEvent> mouseExitEvent =
1999 CreateMouseOrPointerWidgetEvent(mouseEvent,
2000 eMouseExitFromWidget,
2001 mouseEvent->mRelatedTarget);
2002 mouseExitEvent->mExitFrom =
2003 Some(WidgetMouseEvent::ePuppetParentToPuppetChild);
2004 commonAncestor->SendRealMouseEvent(*mouseExitEvent);
2005 }
2006 }
2007 }
2008
2009 if (mouseEvent->mMessage != eMouseExitFromWidget &&
2010 mouseEvent->mMessage != eMouseEnterIntoWidget) {
2011 // This is to make cursor would be updated correctly.
2012 remote->MouseEnterIntoWidget();
2013 }
2014 }
2015
2016 remote->SendRealMouseEvent(*mouseEvent);
2017 return;
2018 }
2019 case eKeyboardEventClass: {
2020 auto* keyboardEvent = aEvent->AsKeyboardEvent();
2021 if (aEvent->mMessage == eKeyUp) {
2022 HandleKeyUpInteraction(keyboardEvent);
2023 }
2024 remote->SendRealKeyEvent(*keyboardEvent);
2025 return;
2026 }
2027 case eWheelEventClass: {
2028 if (BrowserParent* pointerLockedRemote =
2029 PointerLockManager::GetLockedRemoteTarget()) {
2030 remote = pointerLockedRemote;
2031 }
2032 remote->SendMouseWheelEvent(*aEvent->AsWheelEvent());
2033 return;
2034 }
2035 case eTouchEventClass: {
2036 // Let the child process synthesize a mouse event if needed, and
2037 // ensure we don't synthesize one in this process.
2038 *aStatus = nsEventStatus_eConsumeNoDefault;
2039 remote->SendRealTouchEvent(*aEvent->AsTouchEvent());
2040 return;
2041 }
2042 case eDragEventClass: {
2043 RefPtr<BrowserParent> browserParent = remote;
2044 browserParent->MaybeInvokeDragSession(aEvent->mMessage);
2045
2046 RefPtr<nsIWidget> widget = browserParent->GetTopLevelWidget();
2047 nsCOMPtr<nsIDragSession> dragSession =
2048 nsContentUtils::GetDragSession(widget);
2049 uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
2050 uint32_t action = nsIDragService::DRAGDROP_ACTION_NONE;
2051 nsCOMPtr<nsIPrincipal> principal;
2052 nsCOMPtr<nsIContentSecurityPolicy> csp;
2053
2054 if (dragSession) {
2055 dragSession->DragEventDispatchedToChildProcess();
2056 dragSession->GetDragAction(&action);
2057 dragSession->GetTriggeringPrincipal(getter_AddRefs(principal));
2058 dragSession->GetCsp(getter_AddRefs(csp));
2059 RefPtr<DataTransfer> initialDataTransfer =
2060 dragSession->GetDataTransfer();
2061 if (initialDataTransfer) {
2062 dropEffect = initialDataTransfer->DropEffectInt();
2063 }
2064 }
2065
2066 browserParent->SendRealDragEvent(*aEvent->AsDragEvent(), action,
2067 dropEffect, principal, csp);
2068 return;
2069 }
2070 default: {
2071 MOZ_CRASH("Attempt to send non-whitelisted event?")do { do { } while (false); MOZ_ReportCrash("" "Attempt to send non-whitelisted event?"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2071); AnnotateMozCrashReason("MOZ_CRASH(" "Attempt to send non-whitelisted event?"
")"); do { *((volatile int*)__null) = 2071; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2072 }
2073 }
2074}
2075
2076bool EventStateManager::IsRemoteTarget(nsIContent* target) {
2077 return BrowserParent::GetFrom(target) || BrowserBridgeChild::GetFrom(target);
2078}
2079
2080bool EventStateManager::IsTopLevelRemoteTarget(nsIContent* target) {
2081 return !!BrowserParent::GetFrom(target);
2082}
2083
2084bool EventStateManager::HandleCrossProcessEvent(WidgetEvent* aEvent,
2085 nsEventStatus* aStatus) {
2086 if (!aEvent->CanBeSentToRemoteProcess()) {
2087 return false;
2088 }
2089
2090 MOZ_ASSERT(!aEvent->HasBeenPostedToRemoteProcess(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEvent->HasBeenPostedToRemoteProcess())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aEvent->HasBeenPostedToRemoteProcess()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aEvent->HasBeenPostedToRemoteProcess()"
" (" "Why do we need to post same event to remote processes again?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2091); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aEvent->HasBeenPostedToRemoteProcess()"
") (" "Why do we need to post same event to remote processes again?"
")"); do { *((volatile int*)__null) = 2091; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2091 "Why do we need to post same event to remote processes again?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEvent->HasBeenPostedToRemoteProcess())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aEvent->HasBeenPostedToRemoteProcess()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aEvent->HasBeenPostedToRemoteProcess()"
" (" "Why do we need to post same event to remote processes again?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2091); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aEvent->HasBeenPostedToRemoteProcess()"
") (" "Why do we need to post same event to remote processes again?"
")"); do { *((volatile int*)__null) = 2091; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2092
2093 // Collect the remote event targets we're going to forward this
2094 // event to.
2095 //
2096 // NB: the elements of |remoteTargets| must be unique, for correctness.
2097 AutoTArray<RefPtr<BrowserParent>, 1> remoteTargets;
2098 if (aEvent->mClass != eTouchEventClass || aEvent->mMessage == eTouchStart) {
2099 // If this event only has one target, and it's remote, add it to
2100 // the array.
2101 nsIFrame* frame = aEvent->mMessage == eDragExit
2102 ? sLastDragOverFrame.GetFrame()
2103 : GetEventTarget();
2104 nsIContent* target = frame ? frame->GetContent() : nullptr;
2105 if (BrowserParent* remoteTarget = BrowserParent::GetFrom(target)) {
2106 remoteTargets.AppendElement(remoteTarget);
2107 }
2108 } else {
2109 // This is a touch event with possibly multiple touch points.
2110 // Each touch point may have its own target. So iterate through
2111 // all of them and collect the unique set of targets for event
2112 // forwarding.
2113 //
2114 // This loop is similar to the one used in
2115 // PresShell::DispatchTouchEvent().
2116 const WidgetTouchEvent::TouchArray& touches =
2117 aEvent->AsTouchEvent()->mTouches;
2118 for (uint32_t i = 0; i < touches.Length(); ++i) {
2119 Touch* touch = touches[i];
2120 // NB: the |mChanged| check is an optimization, subprocesses can
2121 // compute this for themselves. If the touch hasn't changed, we
2122 // may be able to avoid forwarding the event entirely (which is
2123 // not free).
2124 if (!touch || !touch->mChanged) {
2125 continue;
2126 }
2127 nsCOMPtr<EventTarget> targetPtr = touch->mTarget;
2128 if (!targetPtr) {
2129 continue;
2130 }
2131 nsCOMPtr<nsIContent> target = do_QueryInterface(targetPtr);
2132 BrowserParent* remoteTarget = BrowserParent::GetFrom(target);
2133 if (remoteTarget && !remoteTargets.Contains(remoteTarget)) {
2134 remoteTargets.AppendElement(remoteTarget);
2135 }
2136 }
2137 }
2138
2139 if (remoteTargets.Length() == 0) {
2140 return false;
2141 }
2142
2143 // Dispatch the event to the remote target.
2144 for (uint32_t i = 0; i < remoteTargets.Length(); ++i) {
2145 DispatchCrossProcessEvent(aEvent, remoteTargets[i], aStatus);
2146 }
2147 return aEvent->HasBeenPostedToRemoteProcess();
2148}
2149
2150//
2151// CreateClickHoldTimer
2152//
2153// Fire off a timer for determining if the user wants click-hold. This timer
2154// is a one-shot that will be cancelled when the user moves enough to fire
2155// a drag.
2156//
2157void EventStateManager::CreateClickHoldTimer(nsPresContext* inPresContext,
2158 nsIFrame* inDownFrame,
2159 WidgetGUIEvent* inMouseDownEvent) {
2160 if (!inMouseDownEvent->IsTrusted() ||
2161 IsTopLevelRemoteTarget(mGestureDownContent) ||
2162 PointerLockManager::IsLocked()) {
2163 return;
2164 }
2165
2166 // just to be anal (er, safe)
2167 if (mClickHoldTimer) {
2168 mClickHoldTimer->Cancel();
2169 mClickHoldTimer = nullptr;
2170 }
2171
2172 // if content clicked on has a popup, don't even start the timer
2173 // since we'll end up conflicting and both will show.
2174 if (mGestureDownContent &&
2175 nsContentUtils::HasNonEmptyAttr(mGestureDownContent, kNameSpaceID_None,
2176 nsGkAtoms::popup)) {
2177 return;
2178 }
2179
2180 int32_t clickHoldDelay = StaticPrefs::ui_click_hold_context_menus_delay();
2181 NS_NewTimerWithFuncCallback(
2182 getter_AddRefs(mClickHoldTimer), sClickHoldCallback, this, clickHoldDelay,
2183 nsITimer::TYPE_ONE_SHOT, "EventStateManager::CreateClickHoldTimer");
2184} // CreateClickHoldTimer
2185
2186//
2187// KillClickHoldTimer
2188//
2189// Stop the timer that would show the context menu dead in its tracks
2190//
2191void EventStateManager::KillClickHoldTimer() {
2192 if (mClickHoldTimer) {
2193 mClickHoldTimer->Cancel();
2194 mClickHoldTimer = nullptr;
2195 }
2196}
2197
2198//
2199// sClickHoldCallback
2200//
2201// This fires after the mouse has been down for a certain length of time.
2202//
2203void EventStateManager::sClickHoldCallback(nsITimer* aTimer, void* aESM) {
2204 RefPtr<EventStateManager> self = static_cast<EventStateManager*>(aESM);
2205 if (self) {
2206 self->FireContextClick();
2207 }
2208
2209 // NOTE: |aTimer| and |self->mAutoHideTimer| are invalid after calling
2210 // ClosePopup();
2211
2212} // sAutoHideCallback
2213
2214//
2215// FireContextClick
2216//
2217// If we're this far, our timer has fired, which means the mouse has been down
2218// for a certain period of time and has not moved enough to generate a
2219// dragGesture. We can be certain the user wants a context-click at this stage,
2220// so generate a dom event and fire it in.
2221//
2222// After the event fires, check if PreventDefault() has been set on the event
2223// which means that someone either ate the event or put up a context menu. This
2224// is our cue to stop tracking the drag gesture. If we always did this,
2225// draggable items w/out a context menu wouldn't be draggable after a certain
2226// length of time, which is _not_ what we want.
2227//
2228void EventStateManager::FireContextClick() {
2229 if (!mGestureDownContent || !mPresContext || PointerLockManager::IsLocked()) {
2230 return;
2231 }
2232
2233#ifdef XP_MACOSX
2234 // Hack to ensure that we don't show a context menu when the user
2235 // let go of the mouse after a long cpu-hogging operation prevented
2236 // us from handling any OS events. See bug 117589.
2237 if (!CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState,
2238 kCGMouseButtonLeft))
2239 return;
2240#endif
2241
2242 nsEventStatus status = nsEventStatus_eIgnore;
2243
2244 // Dispatch to the DOM. We have to fake out the ESM and tell it that the
2245 // current target frame is actually where the mouseDown occurred, otherwise it
2246 // will use the frame the mouse is currently over which may or may not be
2247 // the same. (Note: saari and I have decided that we don't have to reset
2248 // |mCurrentTarget| when we're through because no one else is doing anything
2249 // more with this event and it will get reset on the very next event to the
2250 // correct frame).
2251 mCurrentTarget = mPresContext->GetPrimaryFrameFor(mGestureDownContent);
2252 // make sure the widget sticks around
2253 nsCOMPtr<nsIWidget> targetWidget;
2254 if (mCurrentTarget && (targetWidget = mCurrentTarget->GetNearestWidget())) {
2255 NS_ASSERTION(do { if (!(mPresContext == mCurrentTarget->PresContext()))
{ NS_DebugBreak(NS_DEBUG_ASSERTION, "a prescontext returned a primary frame that didn't belong to it?"
, "mPresContext == mCurrentTarget->PresContext()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2257); MOZ_PretendNoReturn(); } } while (0)
2256 mPresContext == mCurrentTarget->PresContext(),do { if (!(mPresContext == mCurrentTarget->PresContext()))
{ NS_DebugBreak(NS_DEBUG_ASSERTION, "a prescontext returned a primary frame that didn't belong to it?"
, "mPresContext == mCurrentTarget->PresContext()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2257); MOZ_PretendNoReturn(); } } while (0)
2257 "a prescontext returned a primary frame that didn't belong to it?")do { if (!(mPresContext == mCurrentTarget->PresContext()))
{ NS_DebugBreak(NS_DEBUG_ASSERTION, "a prescontext returned a primary frame that didn't belong to it?"
, "mPresContext == mCurrentTarget->PresContext()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2257); MOZ_PretendNoReturn(); } } while (0)
;
2258
2259 // before dispatching, check that we're not on something that
2260 // doesn't get a context menu
2261 bool allowedToDispatch = true;
2262
2263 if (mGestureDownContent->IsAnyOfXULElements(nsGkAtoms::scrollbar,
2264 nsGkAtoms::scrollbarbutton,
2265 nsGkAtoms::button)) {
2266 allowedToDispatch = false;
2267 } else if (mGestureDownContent->IsXULElement(nsGkAtoms::toolbarbutton)) {
2268 // a <toolbarbutton> that has the container attribute set
2269 // will already have its own dropdown.
2270 if (nsContentUtils::HasNonEmptyAttr(
2271 mGestureDownContent, kNameSpaceID_None, nsGkAtoms::container)) {
2272 allowedToDispatch = false;
2273 } else {
2274 // If the toolbar button has an open menu, don't attempt to open
2275 // a second menu
2276 if (mGestureDownContent->IsElement() &&
2277 mGestureDownContent->AsElement()->AttrValueIs(
2278 kNameSpaceID_None, nsGkAtoms::open, nsGkAtoms::_true,
2279 eCaseMatters)) {
2280 allowedToDispatch = false;
2281 }
2282 }
2283 } else if (mGestureDownContent->IsHTMLElement()) {
2284 if (const auto* formCtrl =
2285 nsIFormControl::FromNode(mGestureDownContent)) {
2286 allowedToDispatch =
2287 formCtrl->IsTextControl(/*aExcludePassword*/ false) ||
2288 formCtrl->ControlType() == FormControlType::InputFile;
2289 } else if (mGestureDownContent->IsAnyOfHTMLElements(
2290 nsGkAtoms::embed, nsGkAtoms::object, nsGkAtoms::label)) {
2291 allowedToDispatch = false;
2292 }
2293 }
2294
2295 if (allowedToDispatch) {
2296 // init the event while mCurrentTarget is still good
2297 Maybe<WidgetPointerEvent> pointerEvent;
2298 Maybe<WidgetMouseEvent> mouseEvent;
2299 if (StaticPrefs::
2300 dom_w3c_pointer_events_dispatch_click_as_pointer_event()) {
2301 pointerEvent.emplace(true, eContextMenu, targetWidget);
2302 } else {
2303 mouseEvent.emplace(true, eContextMenu, targetWidget,
2304 WidgetMouseEvent::eReal);
2305 }
2306 WidgetMouseEvent& event =
2307 pointerEvent.isSome() ? pointerEvent.ref() : mouseEvent.ref();
2308 event.mClickCount = 1;
2309 FillInEventFromGestureDown(&event);
2310
2311 // we need to forget the clicking content and click count for the
2312 // following eMouseUp event when click-holding context menus
2313 LastMouseDownInfo& mouseDownInfo = GetLastMouseDownInfo(event.mButton);
2314 mouseDownInfo.mLastMouseDownContent = nullptr;
2315 mouseDownInfo.mClickCount = 0;
2316 mouseDownInfo.mLastMouseDownInputControlType = Nothing();
2317
2318 // stop selection tracking, we're in control now
2319 if (mCurrentTarget) {
2320 RefPtr<nsFrameSelection> frameSel = mCurrentTarget->GetFrameSelection();
2321
2322 if (frameSel && frameSel->GetDragState()) {
2323 // note that this can cause selection changed events to fire if we're
2324 // in a text field, which will null out mCurrentTarget
2325 frameSel->SetDragState(false);
2326 }
2327 }
2328
2329 AutoHandlingUserInputStatePusher userInpStatePusher(true, &event);
2330
2331 // dispatch to DOM
2332 RefPtr<nsPresContext> presContext = mPresContext;
2333
2334 // The contextmenu event handled by PresShell will apply to elements (not
2335 // all nodes) correctly and will be dispatched to EventStateManager for
2336 // further handling preventing click event and stopping tracking drag
2337 // gesture.
2338 if (RefPtr<PresShell> presShell = presContext->GetPresShell()) {
2339 presShell->HandleEvent(mCurrentTarget, &event, false, &status);
2340 }
2341
2342 // We don't need to dispatch to frame handling because no frames
2343 // watch eContextMenu except for nsMenuFrame and that's only for
2344 // dismissal. That's just as well since we don't really know
2345 // which frame to send it to.
2346 }
2347 }
2348
2349 // stop tracking a drag whatever the event has been handled or not.
2350 StopTrackingDragGesture(true);
2351
2352 KillClickHoldTimer();
2353
2354} // FireContextClick
2355
2356//
2357// BeginTrackingDragGesture
2358//
2359// Record that the mouse has gone down and that we should move to TRACKING state
2360// of d&d gesture tracker.
2361//
2362// We also use this to track click-hold context menus. When the mouse goes down,
2363// fire off a short timer. If the timer goes off and we have yet to fire the
2364// drag gesture (ie, the mouse hasn't moved a certain distance), then we can
2365// assume the user wants a click-hold, so fire a context-click event. We only
2366// want to cancel the drag gesture if the context-click event is handled.
2367//
2368void EventStateManager::BeginTrackingDragGesture(nsPresContext* aPresContext,
2369 WidgetMouseEvent* inDownEvent,
2370 nsIFrame* inDownFrame) {
2371 if (!inDownEvent->mWidget) {
2372 return;
2373 }
2374
2375 // Note that |inDownEvent| could be either a mouse down event or a
2376 // synthesized mouse move event.
2377 SetGestureDownPoint(inDownEvent);
2378
2379 if (inDownFrame) {
2380 inDownFrame->GetContentForEvent(inDownEvent,
2381 getter_AddRefs(mGestureDownContent));
2382
2383 mGestureDownFrameOwner = inDownFrame->GetContent();
2384 if (!mGestureDownFrameOwner) {
2385 mGestureDownFrameOwner = mGestureDownContent;
2386 }
2387 }
2388 mGestureModifiers = inDownEvent->mModifiers;
2389 mGestureDownButtons = inDownEvent->mButtons;
2390 mGestureDownButton = inDownEvent->mButton;
2391
2392 if (inDownEvent->mMessage != eMouseTouchDrag &&
2393 StaticPrefs::ui_click_hold_context_menus()) {
2394 // fire off a timer to track click-hold
2395 CreateClickHoldTimer(aPresContext, inDownFrame, inDownEvent);
2396 }
2397}
2398
2399void EventStateManager::SetGestureDownPoint(WidgetGUIEvent* aEvent) {
2400 mGestureDownPoint =
2401 GetEventRefPoint(aEvent) + aEvent->mWidget->WidgetToScreenOffset();
2402}
2403
2404LayoutDeviceIntPoint EventStateManager::GetEventRefPoint(
2405 WidgetEvent* aEvent) const {
2406 auto touchEvent = aEvent->AsTouchEvent();
2407 return (touchEvent && !touchEvent->mTouches.IsEmpty())
2408 ? aEvent->AsTouchEvent()->mTouches[0]->mRefPoint
2409 : aEvent->mRefPoint;
2410}
2411
2412void EventStateManager::BeginTrackingRemoteDragGesture(
2413 nsIContent* aContent, RemoteDragStartData* aDragStartData) {
2414 mGestureDownContent = aContent;
2415 mGestureDownFrameOwner = aContent;
2416 mGestureDownInTextControl =
2417 aContent && aContent->IsInNativeAnonymousSubtree() &&
2418 TextControlElement::FromNodeOrNull(
2419 aContent->GetClosestNativeAnonymousSubtreeRootParentOrHost());
2420 mGestureDownDragStartData = aDragStartData;
2421}
2422
2423//
2424// StopTrackingDragGesture
2425//
2426// Record that the mouse has gone back up so that we should leave the TRACKING
2427// state of d&d gesture tracker and return to the START state.
2428//
2429void EventStateManager::StopTrackingDragGesture(bool aClearInChildProcesses) {
2430 mGestureDownContent = nullptr;
2431 mGestureDownFrameOwner = nullptr;
2432 mGestureDownInTextControl = false;
2433 mGestureDownDragStartData = nullptr;
2434
2435 // If a content process starts a drag but the mouse is released before the
2436 // parent starts the actual drag, the content process will think a drag is
2437 // still happening. Inform any child processes with active drags that the drag
2438 // should be stopped.
2439 if (aClearInChildProcesses) {
2440 nsCOMPtr<nsIDragService> dragService =
2441 do_GetService("@mozilla.org/widget/dragservice;1");
2442 if (dragService) {
2443 RefPtr<nsIDragSession> dragSession =
2444 dragService->GetCurrentSession(mPresContext->GetRootWidget());
2445 if (!dragSession) {
2446 // Only notify if there isn't a drag session active.
2447 dragService->RemoveAllBrowsers();
2448 }
2449 }
2450 }
2451}
2452
2453void EventStateManager::FillInEventFromGestureDown(WidgetMouseEvent* aEvent) {
2454 NS_ASSERTION(aEvent->mWidget == mCurrentTarget->GetNearestWidget(),do { if (!(aEvent->mWidget == mCurrentTarget->GetNearestWidget
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Incorrect widget in event"
, "aEvent->mWidget == mCurrentTarget->GetNearestWidget()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2455); MOZ_PretendNoReturn(); } } while (0)
2455 "Incorrect widget in event")do { if (!(aEvent->mWidget == mCurrentTarget->GetNearestWidget
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Incorrect widget in event"
, "aEvent->mWidget == mCurrentTarget->GetNearestWidget()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2455); MOZ_PretendNoReturn(); } } while (0)
;
2456
2457 // Set the coordinates in the new event to the coordinates of
2458 // the old event, adjusted for the fact that the widget might be
2459 // different
2460 aEvent->mRefPoint =
2461 mGestureDownPoint - aEvent->mWidget->WidgetToScreenOffset();
2462 aEvent->mModifiers = mGestureModifiers;
2463 aEvent->mButtons = mGestureDownButtons;
2464 if (aEvent->mMessage == eContextMenu) {
2465 aEvent->mButton = mGestureDownButton;
2466 }
2467}
2468
2469void EventStateManager::MaybeFirePointerCancel(WidgetInputEvent* aEvent) {
2470 RefPtr<PresShell> presShell = mPresContext->GetPresShell();
2471 AutoWeakFrame targetFrame = mCurrentTarget;
2472
2473 if (!presShell || !targetFrame) {
2474 return;
2475 }
2476
2477 nsCOMPtr<nsIContent> content;
2478 targetFrame->GetContentForEvent(aEvent, getter_AddRefs(content));
2479 if (!content) {
2480 return;
2481 }
2482
2483 nsEventStatus status = nsEventStatus_eIgnore;
2484
2485 if (WidgetMouseEvent* aMouseEvent = aEvent->AsMouseEvent()) {
2486 WidgetPointerEvent event(*aMouseEvent);
2487 PointerEventHandler::InitPointerEventFromMouse(&event, aMouseEvent,
2488 ePointerCancel);
2489
2490 event.convertToPointer = false;
2491 presShell->HandleEventWithTarget(&event, targetFrame, content, &status);
2492 } else if (WidgetTouchEvent* aTouchEvent = aEvent->AsTouchEvent()) {
2493 WidgetPointerEvent event(aTouchEvent->IsTrusted(), ePointerCancel,
2494 aTouchEvent->mWidget);
2495
2496 PointerEventHandler::InitPointerEventFromTouch(event, *aTouchEvent,
2497 *aTouchEvent->mTouches[0]);
2498
2499 event.convertToPointer = false;
2500 presShell->HandleEventWithTarget(&event, targetFrame, content, &status);
2501 } else {
2502 MOZ_ASSERT(false)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2502); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ")")
; do { *((volatile int*)__null) = 2502; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2503 }
2504
2505 // HandleEventWithTarget clears out mCurrentTarget, which may be used in the
2506 // caller GenerateDragGesture. We have to restore mCurrentTarget.
2507 mCurrentTarget = targetFrame;
2508}
2509
2510bool EventStateManager::IsEventOutsideDragThreshold(
2511 WidgetInputEvent* aEvent) const {
2512 static int32_t sPixelThresholdX = 0;
2513 static int32_t sPixelThresholdY = 0;
2514
2515 if (!sPixelThresholdX) {
2516 sPixelThresholdX =
2517 LookAndFeel::GetInt(LookAndFeel::IntID::DragThresholdX, 0);
2518 sPixelThresholdY =
2519 LookAndFeel::GetInt(LookAndFeel::IntID::DragThresholdY, 0);
2520 if (sPixelThresholdX <= 0) {
2521 sPixelThresholdX = 5;
2522 }
2523 if (sPixelThresholdY <= 0) {
2524 sPixelThresholdY = 5;
2525 }
2526 }
2527
2528 LayoutDeviceIntPoint pt =
2529 aEvent->mWidget->WidgetToScreenOffset() + GetEventRefPoint(aEvent);
2530 LayoutDeviceIntPoint distance = pt - mGestureDownPoint;
2531 return Abs(distance.x) > sPixelThresholdX ||
2532 Abs(distance.y) > sPixelThresholdY;
2533}
2534
2535//
2536// GenerateDragGesture
2537//
2538// If we're in the TRACKING state of the d&d gesture tracker, check the current
2539// position of the mouse in relation to the old one. If we've moved a sufficient
2540// amount from the mouse down, then fire off a drag gesture event.
2541void EventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
2542 WidgetInputEvent* aEvent) {
2543 NS_ASSERTION(aPresContext, "This shouldn't happen.")do { if (!(aPresContext)) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"This shouldn't happen.", "aPresContext", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2543); MOZ_PretendNoReturn(); } } while (0)
;
2544 if (!IsTrackingDragGesture()) {
2545 return;
2546 }
2547
2548 AutoWeakFrame targetFrameBefore = mCurrentTarget;
2549 auto autoRestore = MakeScopeExit([&] { mCurrentTarget = targetFrameBefore; });
2550 mCurrentTarget = mGestureDownFrameOwner->GetPrimaryFrame();
2551
2552 if (!mCurrentTarget || !mCurrentTarget->GetNearestWidget()) {
2553 StopTrackingDragGesture(true);
2554 return;
2555 }
2556
2557 // Check if selection is tracking drag gestures, if so
2558 // don't interfere!
2559 if (mCurrentTarget) {
2560 RefPtr<nsFrameSelection> frameSel = mCurrentTarget->GetFrameSelection();
2561 if (frameSel && frameSel->GetDragState()) {
2562 StopTrackingDragGesture(true);
2563 return;
2564 }
2565 }
2566
2567 // If non-native code is capturing the mouse don't start a drag.
2568 if (PresShell::IsMouseCapturePreventingDrag()) {
2569 StopTrackingDragGesture(true);
2570 return;
2571 }
2572
2573 if (!IsEventOutsideDragThreshold(aEvent)) {
2574 // To keep the old behavior, flush layout even if we don't start dnd.
2575 FlushLayout(aPresContext);
2576 return;
2577 }
2578
2579 if (StaticPrefs::ui_click_hold_context_menus()) {
2580 // stop the click-hold before we fire off the drag gesture, in case
2581 // it takes a long time
2582 KillClickHoldTimer();
2583 }
2584
2585 nsCOMPtr<nsIDocShell> docshell = aPresContext->GetDocShell();
2586 if (!docshell) {
2587 return;
2588 }
2589
2590 nsCOMPtr<nsPIDOMWindowOuter> window = docshell->GetWindow();
2591 if (!window) return;
2592
2593 RefPtr<DataTransfer> dataTransfer =
2594 new DataTransfer(window, eDragStart, /* aIsExternal */ false,
2595 /* aClipboardType */ Nothing());
2596 auto protectDataTransfer = MakeScopeExit([&] {
2597 if (dataTransfer) {
2598 dataTransfer->Disconnect();
2599 }
2600 });
2601
2602 RefPtr<Selection> selection;
2603 RefPtr<RemoteDragStartData> remoteDragStartData;
2604 nsCOMPtr<nsIContent> eventContent, targetContent;
2605 nsCOMPtr<nsIPrincipal> principal;
2606 nsCOMPtr<nsIContentSecurityPolicy> csp;
2607 nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
2608 bool allowEmptyDataTransfer = false;
2609 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(eventContent));
2610 if (eventContent) {
2611 // If the content is a text node in a password field, we shouldn't
2612 // allow to drag its raw text. Note that we've supported drag from
2613 // password fields but dragging data was masked text. So, it doesn't
2614 // make sense anyway.
2615 if (eventContent->IsText() && eventContent->HasFlag(NS_MAYBE_MASKED)) {
2616 // However, it makes sense to allow to drag selected password text
2617 // when copying selected password is allowed because users may want
2618 // to use drag and drop rather than copy and paste when web apps
2619 // request to input password twice for conforming new password but
2620 // they used password generator.
2621 TextEditor* textEditor =
2622 nsContentUtils::GetTextEditorFromAnonymousNodeWithoutCreation(
2623 eventContent);
2624 if (!textEditor || !textEditor->IsCopyToClipboardAllowed()) {
2625 StopTrackingDragGesture(true);
2626 return;
2627 }
2628 }
2629 DetermineDragTargetAndDefaultData(
2630 window, eventContent, dataTransfer, &allowEmptyDataTransfer,
2631 getter_AddRefs(selection), getter_AddRefs(remoteDragStartData),
2632 getter_AddRefs(targetContent), getter_AddRefs(principal),
2633 getter_AddRefs(csp), getter_AddRefs(cookieJarSettings));
2634 }
2635
2636 // Stop tracking the drag gesture now. This should stop us from
2637 // reentering GenerateDragGesture inside DOM event processing.
2638 // Pass false to avoid clearing the child process state since a real
2639 // drag should be starting.
2640 StopTrackingDragGesture(false);
2641
2642 if (!targetContent) return;
2643
2644 // Use our targetContent, now that we've determined it, as the
2645 // parent object of the DataTransfer.
2646 nsCOMPtr<nsIContent> parentContent =
2647 targetContent->FindFirstNonChromeOnlyAccessContent();
2648 dataTransfer->SetParentObject(parentContent);
2649
2650 sLastDragOverFrame = nullptr;
2651 nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget();
2652
2653 // get the widget from the target frame
2654 WidgetDragEvent startEvent(aEvent->IsTrusted(), eDragStart, widget);
2655 startEvent.mFlags.mIsSynthesizedForTests =
2656 aEvent->mFlags.mIsSynthesizedForTests;
2657 FillInEventFromGestureDown(&startEvent);
2658
2659 startEvent.mDataTransfer = dataTransfer;
2660 if (aEvent->AsMouseEvent()) {
2661 startEvent.mInputSource = aEvent->AsMouseEvent()->mInputSource;
2662 } else if (aEvent->AsTouchEvent()) {
2663 startEvent.mInputSource = MouseEvent_Binding::MOZ_SOURCE_TOUCH;
2664 } else {
2665 MOZ_ASSERT(false)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2665); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ")")
; do { *((volatile int*)__null) = 2665; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2666 }
2667
2668 // Dispatch to the DOM. By setting mCurrentTarget we are faking
2669 // out the ESM and telling it that the current target frame is
2670 // actually where the mouseDown occurred, otherwise it will use
2671 // the frame the mouse is currently over which may or may not be
2672 // the same.
2673
2674 // Hold onto old target content through the event and reset after.
2675 nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
2676
2677 // Set the current target to the content for the mouse down
2678 mCurrentTargetContent = targetContent;
2679
2680 // Dispatch the dragstart event to the DOM.
2681 nsEventStatus status = nsEventStatus_eIgnore;
2682 EventDispatcher::Dispatch(targetContent, aPresContext, &startEvent, nullptr,
2683 &status);
2684
2685 WidgetDragEvent* event = &startEvent;
2686
2687 nsCOMPtr<nsIObserverService> observerService =
2688 mozilla::services::GetObserverService();
2689 // Emit observer event to allow addons to modify the DataTransfer
2690 // object.
2691 if (observerService) {
2692 observerService->NotifyObservers(dataTransfer, "on-datatransfer-available",
2693 nullptr);
2694 }
2695
2696 if (status != nsEventStatus_eConsumeNoDefault) {
2697 bool dragStarted = DoDefaultDragStart(aPresContext, event, dataTransfer,
2698 allowEmptyDataTransfer, targetContent,
2699 selection, remoteDragStartData,
2700 principal, csp, cookieJarSettings);
2701 if (dragStarted) {
2702 sActiveESM = nullptr;
2703 MaybeFirePointerCancel(aEvent);
2704 aEvent->StopPropagation();
2705 }
2706 }
2707
2708 // Reset mCurretTargetContent to what it was
2709 mCurrentTargetContent = targetBeforeEvent;
2710
2711 // Now flush all pending notifications, for better responsiveness
2712 // while dragging.
2713 FlushLayout(aPresContext);
2714} // GenerateDragGesture
2715
2716void EventStateManager::DetermineDragTargetAndDefaultData(
2717 nsPIDOMWindowOuter* aWindow, nsIContent* aSelectionTarget,
2718 DataTransfer* aDataTransfer, bool* aAllowEmptyDataTransfer,
2719 Selection** aSelection, RemoteDragStartData** aRemoteDragStartData,
2720 nsIContent** aTargetNode, nsIPrincipal** aPrincipal,
2721 nsIContentSecurityPolicy** aCsp,
2722 nsICookieJarSettings** aCookieJarSettings) {
2723 *aTargetNode = nullptr;
2724 *aAllowEmptyDataTransfer = false;
2725 nsCOMPtr<nsIContent> dragDataNode;
2726
2727 nsIContent* editingElement = aSelectionTarget->IsEditable()
2728 ? aSelectionTarget->GetEditingHost()
2729 : nullptr;
2730
2731 // In chrome, only allow dragging inside editable areas.
2732 bool isChromeContext = !aWindow->GetBrowsingContext()->IsContent();
2733 if (isChromeContext && !editingElement) {
2734 if (mGestureDownDragStartData) {
2735 // A child process started a drag so use any data it assigned for the dnd
2736 // session.
2737 mGestureDownDragStartData->AddInitialDnDDataTo(aDataTransfer, aPrincipal,
2738 aCsp, aCookieJarSettings);
2739 mGestureDownDragStartData.forget(aRemoteDragStartData);
2740 *aAllowEmptyDataTransfer = true;
2741 }
2742 } else {
2743 mGestureDownDragStartData = nullptr;
2744
2745 // GetDragData determines if a selection, link or image in the content
2746 // should be dragged, and places the data associated with the drag in the
2747 // data transfer.
2748 // mGestureDownContent is the node where the mousedown event for the drag
2749 // occurred, and aSelectionTarget is the node to use when a selection is
2750 // used
2751 bool canDrag;
2752 bool wasAlt = (mGestureModifiers & MODIFIER_ALT) != 0;
2753 nsresult rv = nsContentAreaDragDrop::GetDragData(
2754 aWindow, mGestureDownContent, aSelectionTarget, wasAlt, aDataTransfer,
2755 &canDrag, aSelection, getter_AddRefs(dragDataNode), aCsp,
2756 aCookieJarSettings);
2757 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !canDrag) {
2758 return;
2759 }
2760 }
2761
2762 // if GetDragData returned a node, use that as the node being dragged.
2763 // Otherwise, if a selection is being dragged, use the node within the
2764 // selection that was dragged. Otherwise, just use the mousedown target.
2765 nsIContent* dragContent = mGestureDownContent;
2766 if (dragDataNode)
2767 dragContent = dragDataNode;
2768 else if (*aSelection)
2769 dragContent = aSelectionTarget;
2770
2771 nsIContent* originalDragContent = dragContent;
2772
2773 // If a selection isn't being dragged, look for an ancestor with the
2774 // draggable property set. If one is found, use that as the target of the
2775 // drag instead of the node that was clicked on. If a draggable node wasn't
2776 // found, just use the clicked node.
2777 if (!*aSelection) {
2778 while (dragContent) {
2779 if (auto htmlElement = nsGenericHTMLElement::FromNode(dragContent)) {
2780 if (htmlElement->Draggable()) {
2781 // We let draggable elements to trigger dnd even if there is no data
2782 // in the DataTransfer.
2783 *aAllowEmptyDataTransfer = true;
2784 break;
2785 }
2786 } else {
2787 if (dragContent->IsXULElement()) {
2788 // All XUL elements are draggable, so if a XUL element is
2789 // encountered, stop looking for draggable nodes and just use the
2790 // original clicked node instead.
2791 // XXXndeakin
2792 // In the future, we will want to improve this so that XUL has a
2793 // better way to specify whether something is draggable than just
2794 // on/off.
2795 dragContent = mGestureDownContent;
2796 break;
2797 }
2798 // otherwise, it's not an HTML or XUL element, so just keep looking
2799 }
2800 dragContent = dragContent->GetFlattenedTreeParent();
2801 }
2802 }
2803
2804 // if no node in the hierarchy was found to drag, but the GetDragData method
2805 // returned a node, use that returned node. Otherwise, nothing is draggable.
2806 if (!dragContent && dragDataNode) dragContent = dragDataNode;
2807
2808 if (dragContent) {
2809 // if an ancestor node was used instead, clear the drag data
2810 // XXXndeakin rework this a bit. Find a way to just not call GetDragData if
2811 // we don't need to.
2812 if (dragContent != originalDragContent) aDataTransfer->ClearAll();
2813 *aTargetNode = dragContent;
2814 NS_ADDREF(*aTargetNode)(*aTargetNode)->AddRef();
2815 }
2816}
2817
2818bool EventStateManager::DoDefaultDragStart(
2819 nsPresContext* aPresContext, WidgetDragEvent* aDragEvent,
2820 DataTransfer* aDataTransfer, bool aAllowEmptyDataTransfer,
2821 nsIContent* aDragTarget, Selection* aSelection,
2822 RemoteDragStartData* aDragStartData, nsIPrincipal* aPrincipal,
2823 nsIContentSecurityPolicy* aCsp, nsICookieJarSettings* aCookieJarSettings) {
2824 nsCOMPtr<nsIDragService> dragService =
2825 do_GetService("@mozilla.org/widget/dragservice;1");
2826 if (!dragService) return false;
2827
2828 // Default handling for the dragstart event.
2829 //
2830 // First, check if a drag session already exists. This means that the drag
2831 // service was called directly within a draggesture handler. In this case,
2832 // don't do anything more, as it is assumed that the handler is managing
2833 // drag and drop manually. Make sure to return true to indicate that a drag
2834 // began. However, if we're handling drag session for synthesized events,
2835 // we need to initialize some information of the session. Therefore, we
2836 // need to keep going for synthesized case.
2837 if (MOZ_UNLIKELY(!mPresContext)(__builtin_expect(!!(!mPresContext), 0))) {
2838 return true;
2839 }
2840 nsCOMPtr<nsIDragSession> dragSession =
2841 dragService->GetCurrentSession(mPresContext->GetRootWidget());
2842 if (dragSession && !dragSession->IsSynthesizedForTests()) {
2843 return true;
2844 }
2845
2846 // No drag session is currently active, so check if a handler added
2847 // any items to be dragged. If not, there isn't anything to drag.
2848 uint32_t count = 0;
2849 if (aDataTransfer) {
2850 count = aDataTransfer->MozItemCount();
2851 }
2852 if (!aAllowEmptyDataTransfer && !count) {
2853 return false;
2854 }
2855
2856 // Get the target being dragged, which may not be the same as the
2857 // target of the mouse event. If one wasn't set in the
2858 // aDataTransfer during the event handler, just use the original
2859 // target instead.
2860 nsCOMPtr<nsIContent> dragTarget = aDataTransfer->GetDragTarget();
2861 if (!dragTarget) {
2862 dragTarget = aDragTarget;
2863 if (!dragTarget) {
2864 return false;
2865 }
2866 }
2867
2868 // check which drag effect should initially be used. If the effect was not
2869 // set, just use all actions, otherwise Windows won't allow a drop.
2870 uint32_t action = aDataTransfer->EffectAllowedInt();
2871 if (action == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED) {
2872 action = nsIDragService::DRAGDROP_ACTION_COPY |
2873 nsIDragService::DRAGDROP_ACTION_MOVE |
2874 nsIDragService::DRAGDROP_ACTION_LINK;
2875 }
2876
2877 // get any custom drag image that was set
2878 int32_t imageX, imageY;
2879 RefPtr<Element> dragImage = aDataTransfer->GetDragImage(&imageX, &imageY);
2880
2881 nsCOMPtr<nsIArray> transArray = aDataTransfer->GetTransferables(dragTarget);
2882 if (!transArray) {
2883 return false;
2884 }
2885
2886 RefPtr<DataTransfer> dataTransfer;
2887 if (!dragSession) {
2888 // After this function returns, the DataTransfer will be cleared so it
2889 // appears empty to content. We need to pass a DataTransfer into the Drag
2890 // Session, so we need to make a copy.
2891 aDataTransfer->Clone(aDragTarget, eDrop, aDataTransfer->MozUserCancelled(),
2892 false, getter_AddRefs(dataTransfer));
2893
2894 // Copy over the drop effect, as Clone doesn't copy it for us.
2895 dataTransfer->SetDropEffectInt(aDataTransfer->DropEffectInt());
2896 } else {
2897 MOZ_ASSERT(dragSession->IsSynthesizedForTests())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(dragSession->IsSynthesizedForTests())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(dragSession->IsSynthesizedForTests()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("dragSession->IsSynthesizedForTests()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2897); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dragSession->IsSynthesizedForTests()"
")"); do { *((volatile int*)__null) = 2897; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2898 MOZ_ASSERT(aDragEvent->mFlags.mIsSynthesizedForTests)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDragEvent->mFlags.mIsSynthesizedForTests)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aDragEvent->mFlags.mIsSynthesizedForTests))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aDragEvent->mFlags.mIsSynthesizedForTests"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2898); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDragEvent->mFlags.mIsSynthesizedForTests"
")"); do { *((volatile int*)__null) = 2898; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2899 // If we're initializing synthesized drag session, we should use given
2900 // DataTransfer as is because it'll be used with following drag events
2901 // in any tests, therefore it should be set to nsIDragSession.dataTransfer
2902 // because it and DragEvent.dataTransfer should be same instance.
2903 dataTransfer = aDataTransfer;
2904 }
2905
2906 // XXXndeakin don't really want to create a new drag DOM event
2907 // here, but we need something to pass to the InvokeDragSession
2908 // methods.
2909 RefPtr<DragEvent> event =
2910 NS_NewDOMDragEvent(dragTarget, aPresContext, aDragEvent);
2911
2912 // Use InvokeDragSessionWithSelection if a selection is being dragged,
2913 // such that the image can be generated from the selected text. However,
2914 // use InvokeDragSessionWithImage if a custom image was set or something
2915 // other than a selection is being dragged.
2916 if (!dragImage && aSelection) {
2917 dragService->InvokeDragSessionWithSelection(
2918 aSelection, aPrincipal, aCsp, aCookieJarSettings, transArray, action,
2919 event, dataTransfer, dragTarget);
2920 } else if (aDragStartData) {
2921 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2921); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 2921; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2922 dragService->InvokeDragSessionWithRemoteImage(
2923 dragTarget, aPrincipal, aCsp, aCookieJarSettings, transArray, action,
2924 aDragStartData, event, dataTransfer);
2925 } else {
2926 dragService->InvokeDragSessionWithImage(
2927 dragTarget, aPrincipal, aCsp, aCookieJarSettings, transArray, action,
2928 dragImage, imageX, imageY, event, dataTransfer);
2929 }
2930
2931 return true;
2932}
2933
2934void EventStateManager::ChangeZoom(bool aIncrease) {
2935 // Send the zoom change to the top level browser so it will be handled by the
2936 // front end in the same way as other zoom actions.
2937 nsIDocShell* docShell = mDocument->GetDocShell();
2938 if (!docShell) {
2939 return;
2940 }
2941
2942 BrowsingContext* bc = docShell->GetBrowsingContext();
2943 if (!bc) {
2944 return;
2945 }
2946
2947 if (XRE_IsParentProcess()) {
2948 bc->Canonical()->DispatchWheelZoomChange(aIncrease);
2949 } else if (BrowserChild* child = BrowserChild::GetFrom(docShell)) {
2950 child->SendWheelZoomChange(aIncrease);
2951 }
2952}
2953
2954void EventStateManager::DoScrollHistory(int32_t direction) {
2955 nsCOMPtr<nsISupports> pcContainer(mPresContext->GetContainerWeak());
2956 if (pcContainer) {
2957 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(pcContainer));
2958 if (webNav) {
2959 // positive direction to go back one step, nonpositive to go forward
2960 // This is doing user-initiated history traversal, hence we want
2961 // to require that history entries we navigate to have user interaction.
2962 if (direction > 0)
2963 webNav->GoBack(StaticPrefs::browser_navigation_requireUserInteraction(),
2964 true);
2965 else
2966 webNav->GoForward(
2967 StaticPrefs::browser_navigation_requireUserInteraction(), true);
2968 }
2969 }
2970}
2971
2972void EventStateManager::DoScrollZoom(nsIFrame* aTargetFrame,
2973 int32_t adjustment) {
2974 // Exclude content in chrome docshells.
2975 nsIContent* content = aTargetFrame->GetContent();
2976 if (content && !nsContentUtils::IsInChromeDocshell(content->OwnerDoc())) {
2977 // Positive adjustment to decrease zoom, negative to increase
2978 const bool increase = adjustment <= 0;
2979 EnsureDocument(mPresContext);
2980 ChangeZoom(increase);
2981 }
2982}
2983
2984static nsIFrame* GetParentFrameToScroll(nsIFrame* aFrame) {
2985 if (!aFrame) return nullptr;
2986
2987 if (aFrame->StyleDisplay()->mPosition == StylePositionProperty::Fixed &&
2988 nsLayoutUtils::IsReallyFixedPos(aFrame)) {
2989 return aFrame->PresShell()->GetRootScrollContainerFrame();
2990 }
2991 return aFrame->GetParent();
2992}
2993
2994void EventStateManager::DispatchLegacyMouseScrollEvents(
2995 nsIFrame* aTargetFrame, WidgetWheelEvent* aEvent, nsEventStatus* aStatus) {
2996 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2996); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 2996; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2997 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2997); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 2997; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2998
2999 if (!aTargetFrame || *aStatus == nsEventStatus_eConsumeNoDefault) {
3000 return;
3001 }
3002
3003 // Ignore mouse wheel transaction for computing legacy mouse wheel
3004 // events' delta value.
3005 // DOM event's delta vales are computed from CSS pixels.
3006 auto scrollAmountInCSSPixels =
3007 CSSIntSize::FromAppUnitsRounded(aEvent->mScrollAmount);
3008
3009 // XXX We don't deal with fractional amount in legacy event, though the
3010 // default action handler (DoScrollText()) deals with it.
3011 // If we implemented such strict computation, we would need additional
3012 // accumulated delta values. It would made the code more complicated.
3013 // And also it would computes different delta values from older version.
3014 // It doesn't make sense to implement such code for legacy events and
3015 // rare cases.
3016 int32_t scrollDeltaX, scrollDeltaY, pixelDeltaX, pixelDeltaY;
3017 switch (aEvent->mDeltaMode) {
3018 case WheelEvent_Binding::DOM_DELTA_PAGE:
3019 scrollDeltaX = !aEvent->mLineOrPageDeltaX
3020 ? 0
3021 : (aEvent->mLineOrPageDeltaX > 0
3022 ? UIEvent_Binding::SCROLL_PAGE_DOWN
3023 : UIEvent_Binding::SCROLL_PAGE_UP);
3024 scrollDeltaY = !aEvent->mLineOrPageDeltaY
3025 ? 0
3026 : (aEvent->mLineOrPageDeltaY > 0
3027 ? UIEvent_Binding::SCROLL_PAGE_DOWN
3028 : UIEvent_Binding::SCROLL_PAGE_UP);
3029 pixelDeltaX = RoundDown(aEvent->mDeltaX * scrollAmountInCSSPixels.width);
3030 pixelDeltaY = RoundDown(aEvent->mDeltaY * scrollAmountInCSSPixels.height);
3031 break;
3032
3033 case WheelEvent_Binding::DOM_DELTA_LINE:
3034 scrollDeltaX = aEvent->mLineOrPageDeltaX;
3035 scrollDeltaY = aEvent->mLineOrPageDeltaY;
3036 pixelDeltaX = RoundDown(aEvent->mDeltaX * scrollAmountInCSSPixels.width);
3037 pixelDeltaY = RoundDown(aEvent->mDeltaY * scrollAmountInCSSPixels.height);
3038 break;
3039
3040 case WheelEvent_Binding::DOM_DELTA_PIXEL:
3041 scrollDeltaX = aEvent->mLineOrPageDeltaX;
3042 scrollDeltaY = aEvent->mLineOrPageDeltaY;
3043 pixelDeltaX = RoundDown(aEvent->mDeltaX);
3044 pixelDeltaY = RoundDown(aEvent->mDeltaY);
3045 break;
3046
3047 default:
3048 MOZ_CRASH("Invalid deltaMode value comes")do { do { } while (false); MOZ_ReportCrash("" "Invalid deltaMode value comes"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3048); AnnotateMozCrashReason("MOZ_CRASH(" "Invalid deltaMode value comes"
")"); do { *((volatile int*)__null) = 3048; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
3049 }
3050
3051 // Send the legacy events in following order:
3052 // 1. Vertical scroll
3053 // 2. Vertical pixel scroll (even if #1 isn't consumed)
3054 // 3. Horizontal scroll (even if #1 and/or #2 are consumed)
3055 // 4. Horizontal pixel scroll (even if #3 isn't consumed)
3056
3057 AutoWeakFrame targetFrame(aTargetFrame);
3058
3059 MOZ_ASSERT(*aStatus != nsEventStatus_eConsumeNoDefault &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault &&
!aEvent->DefaultPrevented())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aStatus != nsEventStatus_eConsumeNoDefault
&& !aEvent->DefaultPrevented()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
" (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3062); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
") (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")"); do {
*((volatile int*)__null) = 3062; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3060 !aEvent->DefaultPrevented(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault &&
!aEvent->DefaultPrevented())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aStatus != nsEventStatus_eConsumeNoDefault
&& !aEvent->DefaultPrevented()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
" (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3062); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
") (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")"); do {
*((volatile int*)__null) = 3062; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3061 "If you make legacy events dispatched for default prevented wheel "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault &&
!aEvent->DefaultPrevented())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aStatus != nsEventStatus_eConsumeNoDefault
&& !aEvent->DefaultPrevented()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
" (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3062); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
") (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")"); do {
*((volatile int*)__null) = 3062; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3062 "event, you need to initialize stateX and stateY")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault &&
!aEvent->DefaultPrevented())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aStatus != nsEventStatus_eConsumeNoDefault
&& !aEvent->DefaultPrevented()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
" (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3062); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
") (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")"); do {
*((volatile int*)__null) = 3062; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
3063 EventState stateX, stateY;
3064 if (scrollDeltaY) {
3065 SendLineScrollEvent(aTargetFrame, aEvent, stateY, scrollDeltaY,
3066 DELTA_DIRECTION_Y);
3067 if (!targetFrame.IsAlive()) {
3068 *aStatus = nsEventStatus_eConsumeNoDefault;
3069 return;
3070 }
3071 }
3072
3073 if (pixelDeltaY) {
3074 SendPixelScrollEvent(aTargetFrame, aEvent, stateY, pixelDeltaY,
3075 DELTA_DIRECTION_Y);
3076 if (!targetFrame.IsAlive()) {
3077 *aStatus = nsEventStatus_eConsumeNoDefault;
3078 return;
3079 }
3080 }
3081
3082 if (scrollDeltaX) {
3083 SendLineScrollEvent(aTargetFrame, aEvent, stateX, scrollDeltaX,
3084 DELTA_DIRECTION_X);
3085 if (!targetFrame.IsAlive()) {
3086 *aStatus = nsEventStatus_eConsumeNoDefault;
3087 return;
3088 }
3089 }
3090
3091 if (pixelDeltaX) {
3092 SendPixelScrollEvent(aTargetFrame, aEvent, stateX, pixelDeltaX,
3093 DELTA_DIRECTION_X);
3094 if (!targetFrame.IsAlive()) {
3095 *aStatus = nsEventStatus_eConsumeNoDefault;
3096 return;
3097 }
3098 }
3099
3100 if (stateY.mDefaultPrevented) {
3101 *aStatus = nsEventStatus_eConsumeNoDefault;
3102 aEvent->PreventDefault(!stateY.mDefaultPreventedByContent);
3103 }
3104
3105 if (stateX.mDefaultPrevented) {
3106 *aStatus = nsEventStatus_eConsumeNoDefault;
3107 aEvent->PreventDefault(!stateX.mDefaultPreventedByContent);
3108 }
3109}
3110
3111void EventStateManager::SendLineScrollEvent(nsIFrame* aTargetFrame,
3112 WidgetWheelEvent* aEvent,
3113 EventState& aState, int32_t aDelta,
3114 DeltaDirection aDeltaDirection) {
3115 nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
3116 if (!targetContent) {
3117 targetContent = GetFocusedElement();
3118 if (!targetContent) {
3119 return;
3120 }
3121 }
3122
3123 while (targetContent->IsText()) {
3124 targetContent = targetContent->GetFlattenedTreeParent();
3125 }
3126
3127 WidgetMouseScrollEvent event(aEvent->IsTrusted(),
3128 eLegacyMouseLineOrPageScroll, aEvent->mWidget);
3129 event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
3130 event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
3131 event.mRefPoint = aEvent->mRefPoint;
3132 event.mTimeStamp = aEvent->mTimeStamp;
3133 event.mModifiers = aEvent->mModifiers;
3134 event.mButtons = aEvent->mButtons;
3135 event.mIsHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
3136 event.mDelta = aDelta;
3137 event.mInputSource = aEvent->mInputSource;
3138
3139 RefPtr<nsPresContext> presContext = aTargetFrame->PresContext();
3140 nsEventStatus status = nsEventStatus_eIgnore;
3141 EventDispatcher::Dispatch(targetContent, presContext, &event, nullptr,
3142 &status);
3143 aState.mDefaultPrevented =
3144 event.DefaultPrevented() || status == nsEventStatus_eConsumeNoDefault;
3145 aState.mDefaultPreventedByContent = event.DefaultPreventedByContent();
3146}
3147
3148void EventStateManager::SendPixelScrollEvent(nsIFrame* aTargetFrame,
3149 WidgetWheelEvent* aEvent,
3150 EventState& aState,
3151 int32_t aPixelDelta,
3152 DeltaDirection aDeltaDirection) {
3153 nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
3154 if (!targetContent) {
3155 targetContent = GetFocusedElement();
3156 if (!targetContent) {
3157 return;
3158 }
3159 }
3160
3161 while (targetContent->IsText()) {
3162 targetContent = targetContent->GetFlattenedTreeParent();
3163 }
3164
3165 WidgetMouseScrollEvent event(aEvent->IsTrusted(), eLegacyMousePixelScroll,
3166 aEvent->mWidget);
3167 event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
3168 event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
3169 event.mRefPoint = aEvent->mRefPoint;
3170 event.mTimeStamp = aEvent->mTimeStamp;
3171 event.mModifiers = aEvent->mModifiers;
3172 event.mButtons = aEvent->mButtons;
3173 event.mIsHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
3174 event.mDelta = aPixelDelta;
3175 event.mInputSource = aEvent->mInputSource;
3176
3177 RefPtr<nsPresContext> presContext = aTargetFrame->PresContext();
3178 nsEventStatus status = nsEventStatus_eIgnore;
3179 EventDispatcher::Dispatch(targetContent, presContext, &event, nullptr,
3180 &status);
3181 aState.mDefaultPrevented =
3182 event.DefaultPrevented() || status == nsEventStatus_eConsumeNoDefault;
3183 aState.mDefaultPreventedByContent = event.DefaultPreventedByContent();
3184}
3185
3186ScrollContainerFrame*
3187EventStateManager::ComputeScrollTargetAndMayAdjustWheelEvent(
3188 nsIFrame* aTargetFrame, WidgetWheelEvent* aEvent,
3189 ComputeScrollTargetOptions aOptions) {
3190 return ComputeScrollTargetAndMayAdjustWheelEvent(
3191 aTargetFrame, aEvent->mDeltaX, aEvent->mDeltaY, aEvent, aOptions);
3192}
3193
3194// Overload ComputeScrollTargetAndMayAdjustWheelEvent method to allow passing
3195// "test" dx and dy when looking for which scrollbarmediators to activate when
3196// two finger down on trackpad and before any actual motion
3197ScrollContainerFrame*
3198EventStateManager::ComputeScrollTargetAndMayAdjustWheelEvent(
3199 nsIFrame* aTargetFrame, double aDirectionX, double aDirectionY,
3200 WidgetWheelEvent* aEvent, ComputeScrollTargetOptions aOptions) {
3201 bool isAutoDir = false;
3202 bool honoursRoot = false;
3203 if (MAY_BE_ADJUSTED_BY_AUTO_DIR & aOptions) {
3204 // If the scroll is respected as auto-dir, aDirection* should always be
3205 // equivalent to the event's delta vlaues(Currently, there are only one case
3206 // where aDirection*s have different values from the widget wheel event's
3207 // original delta values and the only case isn't auto-dir, see
3208 // ScrollbarsForWheel::TemporarilyActivateAllPossibleScrollTargets).
3209 MOZ_ASSERT(aDirectionX == aEvent->mDeltaX &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDirectionX == aEvent->mDeltaX && aDirectionY
== aEvent->mDeltaY)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDirectionX == aEvent->mDeltaX
&& aDirectionY == aEvent->mDeltaY))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aDirectionX == aEvent->mDeltaX && aDirectionY == aEvent->mDeltaY"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3210); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDirectionX == aEvent->mDeltaX && aDirectionY == aEvent->mDeltaY"
")"); do { *((volatile int*)__null) = 3210; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3210 aDirectionY == aEvent->mDeltaY)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDirectionX == aEvent->mDeltaX && aDirectionY
== aEvent->mDeltaY)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDirectionX == aEvent->mDeltaX
&& aDirectionY == aEvent->mDeltaY))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aDirectionX == aEvent->mDeltaX && aDirectionY == aEvent->mDeltaY"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3210); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDirectionX == aEvent->mDeltaX && aDirectionY == aEvent->mDeltaY"
")"); do { *((volatile int*)__null) = 3210; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3211
3212 WheelDeltaAdjustmentStrategy strategy =
3213 GetWheelDeltaAdjustmentStrategy(*aEvent);
3214 switch (strategy) {
3215 case WheelDeltaAdjustmentStrategy::eAutoDir:
3216 isAutoDir = true;
3217 honoursRoot = false;
3218 break;
3219 case WheelDeltaAdjustmentStrategy::eAutoDirWithRootHonour:
3220 isAutoDir = true;
3221 honoursRoot = true;
3222 break;
3223 default:
3224 break;
3225 }
3226 }
3227
3228 if (aOptions & PREFER_MOUSE_WHEEL_TRANSACTION) {
3229 // If the user recently scrolled with the mousewheel, then they probably
3230 // want to scroll the same view as before instead of the view under the
3231 // cursor. WheelTransaction tracks the frame currently being
3232 // scrolled with the mousewheel. We consider the transaction ended when the
3233 // mouse moves more than "mousewheel.transaction.ignoremovedelay"
3234 // milliseconds after the last scroll operation, or any time the mouse moves
3235 // out of the frame, or when more than "mousewheel.transaction.timeout"
3236 // milliseconds have passed after the last operation, even if the mouse
3237 // hasn't moved.
3238 nsIFrame* lastScrollFrame = WheelTransaction::GetScrollTargetFrame();
3239 if (lastScrollFrame) {
3240 ScrollContainerFrame* scrollContainerFrame =
3241 lastScrollFrame->GetScrollTargetFrame();
3242 if (scrollContainerFrame) {
3243 if (isAutoDir) {
3244 ESMAutoDirWheelDeltaAdjuster adjuster(*aEvent, *lastScrollFrame,
3245 honoursRoot);
3246 // Note that calling this function will not always cause the delta to
3247 // be adjusted, it only adjusts the delta when it should, because
3248 // Adjust() internally calls ShouldBeAdjusted() before making
3249 // adjustment.
3250 adjuster.Adjust();
3251 }
3252 return scrollContainerFrame;
3253 }
3254 }
3255 }
3256
3257 // If the event doesn't cause scroll actually, we cannot find scroll target
3258 // because we check if the event can cause scroll actually on each found
3259 // scrollable frame.
3260 if (!aDirectionX && !aDirectionY) {
3261 return nullptr;
3262 }
3263
3264 bool checkIfScrollableX;
3265 bool checkIfScrollableY;
3266 if (isAutoDir) {
3267 // Always check the frame's scrollability in both the two directions for an
3268 // auto-dir scroll. That is, for an auto-dir scroll,
3269 // PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS and
3270 // PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS should be ignored.
3271 checkIfScrollableX = true;
3272 checkIfScrollableY = true;
3273 } else {
3274 checkIfScrollableX =
3275 aDirectionX &&
3276 (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS);
3277 checkIfScrollableY =
3278 aDirectionY &&
3279 (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS);
3280 }
3281
3282 nsIFrame* scrollFrame = !(aOptions & START_FROM_PARENT)
3283 ? aTargetFrame
3284 : GetParentFrameToScroll(aTargetFrame);
3285 for (; scrollFrame; scrollFrame = GetParentFrameToScroll(scrollFrame)) {
3286 // Check whether the frame wants to provide us with a scrollable view.
3287 ScrollContainerFrame* scrollContainerFrame =
3288 scrollFrame->GetScrollTargetFrame();
3289 if (!scrollContainerFrame) {
3290 nsMenuPopupFrame* menuPopupFrame = do_QueryFrame(scrollFrame);
3291 if (menuPopupFrame) {
3292 return nullptr;
3293 }
3294 continue;
3295 }
3296
3297 if (!checkIfScrollableX && !checkIfScrollableY) {
3298 return scrollContainerFrame;
3299 }
3300
3301 // If the frame disregards the direction the user is trying to scroll, then
3302 // it should just bubbles the scroll event up to its parental scroll frame
3303
3304 Maybe<layers::ScrollDirection> disregardedDirection =
3305 WheelHandlingUtils::GetDisregardedWheelScrollDirection(scrollFrame);
3306 if (disregardedDirection) {
3307 switch (disregardedDirection.ref()) {
3308 case layers::ScrollDirection::eHorizontal:
3309 if (checkIfScrollableX) {
3310 continue;
3311 }
3312 break;
3313 case layers::ScrollDirection::eVertical:
3314 if (checkIfScrollableY) {
3315 continue;
3316 }
3317 break;
3318 }
3319 }
3320
3321 layers::ScrollDirections directions =
3322 scrollContainerFrame
3323 ->GetAvailableScrollingDirectionsForUserInputEvents();
3324 if ((!(directions.contains(layers::ScrollDirection::eVertical)) &&
3325 !(directions.contains(layers::ScrollDirection::eHorizontal))) ||
3326 (checkIfScrollableY && !checkIfScrollableX &&
3327 !(directions.contains(layers::ScrollDirection::eVertical))) ||
3328 (checkIfScrollableX && !checkIfScrollableY &&
3329 !(directions.contains(layers::ScrollDirection::eHorizontal)))) {
3330 continue;
3331 }
3332
3333 // Computes whether the currently checked frame is scrollable by this wheel
3334 // event.
3335 bool canScroll = false;
3336 if (isAutoDir) {
3337 ESMAutoDirWheelDeltaAdjuster adjuster(*aEvent, *scrollFrame, honoursRoot);
3338 if (adjuster.ShouldBeAdjusted()) {
3339 adjuster.Adjust();
3340 canScroll = true;
3341 } else if (WheelHandlingUtils::CanScrollOn(scrollContainerFrame,
3342 aDirectionX, aDirectionY)) {
3343 canScroll = true;
3344 }
3345 } else if (WheelHandlingUtils::CanScrollOn(scrollContainerFrame,
3346 aDirectionX, aDirectionY)) {
3347 canScroll = true;
3348 }
3349
3350 if (canScroll) {
3351 return scrollContainerFrame;
3352 }
3353
3354 // Where we are at is the block ending in a for loop.
3355 // The current frame has been checked to be unscrollable by this wheel
3356 // event, continue the loop to check its parent, if any.
3357 }
3358
3359 nsIFrame* newFrame = nsLayoutUtils::GetCrossDocParentFrameInProcess(
3360 aTargetFrame->PresShell()->GetRootFrame());
3361 aOptions =
3362 static_cast<ComputeScrollTargetOptions>(aOptions & ~START_FROM_PARENT);
3363 if (!newFrame) {
3364 return nullptr;
3365 }
3366 return ComputeScrollTargetAndMayAdjustWheelEvent(newFrame, aEvent, aOptions);
3367}
3368
3369nsSize EventStateManager::GetScrollAmount(
3370 nsPresContext* aPresContext, WidgetWheelEvent* aEvent,
3371 ScrollContainerFrame* aScrollContainerFrame) {
3372 MOZ_ASSERT(aPresContext)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresContext))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPresContext", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3372); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresContext"
")"); do { *((volatile int*)__null) = 3372; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3373 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3373); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 3373; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3374
3375 const bool isPage = aEvent->mDeltaMode == WheelEvent_Binding::DOM_DELTA_PAGE;
3376 if (!aScrollContainerFrame) {
3377 // If there is no scrollable frame, we should use root, see below.
3378 aScrollContainerFrame =
3379 aPresContext->PresShell()->GetRootScrollContainerFrame();
3380 }
3381
3382 if (aScrollContainerFrame) {
3383 return isPage ? aScrollContainerFrame->GetPageScrollAmount()
3384 : aScrollContainerFrame->GetLineScrollAmount();
3385 }
3386
3387 // If there is no scrollable frame and page scrolling, use viewport size.
3388 if (isPage) {
3389 return aPresContext->GetVisibleArea().Size();
3390 }
3391
3392 // Otherwise use root frame's font metrics.
3393 //
3394 // FIXME(emilio): Should this use the root element's style frame? The root
3395 // frame will always have the initial font. Then again it should never matter
3396 // for content, we should always have a root scrollable frame in html
3397 // documents.
3398 nsIFrame* rootFrame = aPresContext->PresShell()->GetRootFrame();
3399 if (!rootFrame) {
3400 return nsSize(0, 0);
3401 }
3402 RefPtr<nsFontMetrics> fm =
3403 nsLayoutUtils::GetInflatedFontMetricsForFrame(rootFrame);
3404 NS_ENSURE_TRUE(fm, nsSize(0, 0))do { if ((__builtin_expect(!!(!(fm)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "fm" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3404); return nsSize(0, 0); } } while (false)
;
3405 return nsSize(fm->AveCharWidth(), fm->MaxHeight());
3406}
3407
3408void EventStateManager::DoScrollText(
3409 ScrollContainerFrame* aScrollContainerFrame, WidgetWheelEvent* aEvent) {
3410 MOZ_ASSERT(aScrollContainerFrame)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aScrollContainerFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aScrollContainerFrame))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aScrollContainerFrame"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3410); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aScrollContainerFrame"
")"); do { *((volatile int*)__null) = 3410; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3411 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3411); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 3411; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3412
3413 AutoWeakFrame scrollFrameWeak(aScrollContainerFrame);
3414 AutoWeakFrame eventFrameWeak(mCurrentTarget);
3415 if (!WheelTransaction::WillHandleDefaultAction(aEvent, scrollFrameWeak,
3416 eventFrameWeak)) {
3417 return;
3418 }
3419
3420 // Default action's actual scroll amount should be computed from device
3421 // pixels.
3422 nsPresContext* pc = aScrollContainerFrame->PresContext();
3423 nsSize scrollAmount = GetScrollAmount(pc, aEvent, aScrollContainerFrame);
3424 nsIntSize scrollAmountInDevPixels(
3425 pc->AppUnitsToDevPixels(scrollAmount.width),
3426 pc->AppUnitsToDevPixels(scrollAmount.height));
3427 nsIntPoint actualDevPixelScrollAmount =
3428 DeltaAccumulator::GetInstance()->ComputeScrollAmountForDefaultAction(
3429 aEvent, scrollAmountInDevPixels);
3430
3431 // Don't scroll around the axis whose overflow style is hidden.
3432 ScrollStyles overflowStyle = aScrollContainerFrame->GetScrollStyles();
3433 if (overflowStyle.mHorizontal == StyleOverflow::Hidden) {
3434 actualDevPixelScrollAmount.x = 0;
3435 }
3436 if (overflowStyle.mVertical == StyleOverflow::Hidden) {
3437 actualDevPixelScrollAmount.y = 0;
3438 }
3439
3440 ScrollSnapFlags snapFlags = ScrollSnapFlags::Disabled;
3441 mozilla::ScrollOrigin origin = mozilla::ScrollOrigin::NotSpecified;
3442 switch (aEvent->mDeltaMode) {
3443 case WheelEvent_Binding::DOM_DELTA_LINE:
3444 origin = mozilla::ScrollOrigin::MouseWheel;
3445 snapFlags = ScrollSnapFlags::IntendedDirection;
3446 break;
3447 case WheelEvent_Binding::DOM_DELTA_PAGE:
3448 origin = mozilla::ScrollOrigin::Pages;
3449 snapFlags = ScrollSnapFlags::IntendedDirection |
3450 ScrollSnapFlags::IntendedEndPosition;
3451 break;
3452 case WheelEvent_Binding::DOM_DELTA_PIXEL:
3453 origin = mozilla::ScrollOrigin::Pixels;
3454 break;
3455 default:
3456 MOZ_CRASH("Invalid deltaMode value comes")do { do { } while (false); MOZ_ReportCrash("" "Invalid deltaMode value comes"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3456); AnnotateMozCrashReason("MOZ_CRASH(" "Invalid deltaMode value comes"
")"); do { *((volatile int*)__null) = 3456; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
3457 }
3458
3459 // We shouldn't scroll more one page at once except when over one page scroll
3460 // is allowed for the event.
3461 nsSize pageSize = aScrollContainerFrame->GetPageScrollAmount();
3462 nsIntSize devPixelPageSize(pc->AppUnitsToDevPixels(pageSize.width),
3463 pc->AppUnitsToDevPixels(pageSize.height));
3464 if (!WheelPrefs::GetInstance()->IsOverOnePageScrollAllowedX(aEvent) &&
3465 DeprecatedAbs(actualDevPixelScrollAmount.x.value) >
3466 devPixelPageSize.width) {
3467 actualDevPixelScrollAmount.x = (actualDevPixelScrollAmount.x >= 0)
3468 ? devPixelPageSize.width
3469 : -devPixelPageSize.width;
3470 }
3471
3472 if (!WheelPrefs::GetInstance()->IsOverOnePageScrollAllowedY(aEvent) &&
3473 DeprecatedAbs(actualDevPixelScrollAmount.y.value) >
3474 devPixelPageSize.height) {
3475 actualDevPixelScrollAmount.y = (actualDevPixelScrollAmount.y >= 0)
3476 ? devPixelPageSize.height
3477 : -devPixelPageSize.height;
3478 }
3479
3480 bool isDeltaModePixel =
3481 (aEvent->mDeltaMode == WheelEvent_Binding::DOM_DELTA_PIXEL);
3482
3483 ScrollMode mode;
3484 switch (aEvent->mScrollType) {
3485 case WidgetWheelEvent::SCROLL_DEFAULT:
3486 if (isDeltaModePixel) {
3487 mode = ScrollMode::Normal;
3488 } else if (aEvent->mFlags.mHandledByAPZ) {
3489 mode = ScrollMode::SmoothMsd;
3490 } else {
3491 mode = ScrollMode::Smooth;
3492 }
3493 break;
3494 case WidgetWheelEvent::SCROLL_SYNCHRONOUSLY:
3495 mode = ScrollMode::Instant;
3496 break;
3497 case WidgetWheelEvent::SCROLL_ASYNCHRONOUSLY:
3498 mode = ScrollMode::Normal;
3499 break;
3500 case WidgetWheelEvent::SCROLL_SMOOTHLY:
3501 mode = ScrollMode::Smooth;
3502 break;
3503 default:
3504 MOZ_CRASH("Invalid mScrollType value comes")do { do { } while (false); MOZ_ReportCrash("" "Invalid mScrollType value comes"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3504); AnnotateMozCrashReason("MOZ_CRASH(" "Invalid mScrollType value comes"
")"); do { *((volatile int*)__null) = 3504; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
3505 }
3506
3507 ScrollContainerFrame::ScrollMomentum momentum =
3508 aEvent->mIsMomentum ? ScrollContainerFrame::SYNTHESIZED_MOMENTUM_EVENT
3509 : ScrollContainerFrame::NOT_MOMENTUM;
3510
3511 nsIntPoint overflow;
3512 aScrollContainerFrame->ScrollBy(actualDevPixelScrollAmount,
3513 ScrollUnit::DEVICE_PIXELS, mode, &overflow,
3514 origin, momentum, snapFlags);
3515
3516 if (!scrollFrameWeak.IsAlive()) {
3517 // If the scroll causes changing the layout, we can think that the event
3518 // has been completely consumed by the content. Then, users probably don't
3519 // want additional action.
3520 aEvent->mOverflowDeltaX = aEvent->mOverflowDeltaY = 0;
3521 } else if (isDeltaModePixel) {
3522 aEvent->mOverflowDeltaX = overflow.x;
3523 aEvent->mOverflowDeltaY = overflow.y;
3524 } else {
3525 aEvent->mOverflowDeltaX =
3526 static_cast<double>(overflow.x) / scrollAmountInDevPixels.width;
3527 aEvent->mOverflowDeltaY =
3528 static_cast<double>(overflow.y) / scrollAmountInDevPixels.height;
3529 }
3530
3531 // If CSS overflow properties caused not to scroll, the overflowDelta* values
3532 // should be same as delta* values since they may be used as gesture event by
3533 // widget. However, if there is another scrollable element in the ancestor
3534 // along the axis, probably users don't want the operation to cause
3535 // additional action such as moving history. In such case, overflowDelta
3536 // values should stay zero.
3537 if (scrollFrameWeak.IsAlive()) {
3538 if (aEvent->mDeltaX && overflowStyle.mHorizontal == StyleOverflow::Hidden &&
3539 !ComputeScrollTargetAndMayAdjustWheelEvent(
3540 aScrollContainerFrame, aEvent,
3541 COMPUTE_SCROLLABLE_ANCESTOR_ALONG_X_AXIS_WITH_AUTO_DIR)) {
3542 aEvent->mOverflowDeltaX = aEvent->mDeltaX;
3543 }
3544 if (aEvent->mDeltaY && overflowStyle.mVertical == StyleOverflow::Hidden &&
3545 !ComputeScrollTargetAndMayAdjustWheelEvent(
3546 aScrollContainerFrame, aEvent,
3547 COMPUTE_SCROLLABLE_ANCESTOR_ALONG_Y_AXIS_WITH_AUTO_DIR)) {
3548 aEvent->mOverflowDeltaY = aEvent->mDeltaY;
3549 }
3550 }
3551
3552 NS_ASSERTION(do { if (!(aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX
> 0) == (aEvent->mDeltaX > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaX is different from the scroll direction"
, "aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3555); MOZ_PretendNoReturn(); } } while (0)
3553 aEvent->mOverflowDeltaX == 0 ||do { if (!(aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX
> 0) == (aEvent->mDeltaX > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaX is different from the scroll direction"
, "aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3555); MOZ_PretendNoReturn(); } } while (0)
3554 (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0),do { if (!(aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX
> 0) == (aEvent->mDeltaX > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaX is different from the scroll direction"
, "aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3555); MOZ_PretendNoReturn(); } } while (0)
3555 "The sign of mOverflowDeltaX is different from the scroll direction")do { if (!(aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX
> 0) == (aEvent->mDeltaX > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaX is different from the scroll direction"
, "aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3555); MOZ_PretendNoReturn(); } } while (0)
;
3556 NS_ASSERTION(do { if (!(aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY
> 0) == (aEvent->mDeltaY > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaY is different from the scroll direction"
, "aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3559); MOZ_PretendNoReturn(); } } while (0)
3557 aEvent->mOverflowDeltaY == 0 ||do { if (!(aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY
> 0) == (aEvent->mDeltaY > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaY is different from the scroll direction"
, "aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3559); MOZ_PretendNoReturn(); } } while (0)
3558 (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0),do { if (!(aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY
> 0) == (aEvent->mDeltaY > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaY is different from the scroll direction"
, "aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3559); MOZ_PretendNoReturn(); } } while (0)
3559 "The sign of mOverflowDeltaY is different from the scroll direction")do { if (!(aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY
> 0) == (aEvent->mDeltaY > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaY is different from the scroll direction"
, "aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3559); MOZ_PretendNoReturn(); } } while (0)
;
3560
3561 WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(aEvent);
3562}
3563
3564void EventStateManager::DecideGestureEvent(WidgetGestureNotifyEvent* aEvent,
3565 nsIFrame* targetFrame) {
3566 NS_ASSERTION(aEvent->mMessage == eGestureNotify,do { if (!(aEvent->mMessage == eGestureNotify)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "DecideGestureEvent called with a non-gesture event"
, "aEvent->mMessage == eGestureNotify", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3567); MOZ_PretendNoReturn(); } } while (0)
3567 "DecideGestureEvent called with a non-gesture event")do { if (!(aEvent->mMessage == eGestureNotify)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "DecideGestureEvent called with a non-gesture event"
, "aEvent->mMessage == eGestureNotify", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3567); MOZ_PretendNoReturn(); } } while (0)
;
3568
3569 /* Check the ancestor tree to decide if any frame is willing* to receive
3570 * a MozPixelScroll event. If that's the case, the current touch gesture
3571 * will be used as a pan gesture; otherwise it will be a regular
3572 * mousedown/mousemove/click event.
3573 *
3574 * *willing: determine if it makes sense to pan the element using scroll
3575 * events:
3576 * - For web content: if there are any visible scrollbars on the touch point
3577 * - For XUL: if it's an scrollable element that can currently scroll in some
3578 * direction.
3579 *
3580 * Note: we'll have to one-off various cases to ensure a good usable behavior
3581 */
3582 WidgetGestureNotifyEvent::PanDirection panDirection =
3583 WidgetGestureNotifyEvent::ePanNone;
3584 bool displayPanFeedback = false;
3585 for (nsIFrame* current = targetFrame; current;
3586 current = nsLayoutUtils::GetCrossDocParentFrame(current)) {
3587 // e10s - mark remote content as pannable. This is a work around since
3588 // we don't have access to remote frame scroll info here. Apz data may
3589 // assist is solving this.
3590 if (current && IsTopLevelRemoteTarget(current->GetContent())) {
3591 panDirection = WidgetGestureNotifyEvent::ePanBoth;
3592 // We don't know when we reach bounds, so just disable feedback for now.
3593 displayPanFeedback = false;
3594 break;
3595 }
3596
3597 LayoutFrameType currentFrameType = current->Type();
3598
3599 // Scrollbars should always be draggable
3600 if (currentFrameType == LayoutFrameType::Scrollbar) {
3601 panDirection = WidgetGestureNotifyEvent::ePanNone;
3602 break;
3603 }
3604
3605 // Special check for trees
3606 if (nsTreeBodyFrame* treeFrame = do_QueryFrame(current)) {
3607 if (treeFrame->GetHorizontalOverflow()) {
3608 panDirection = WidgetGestureNotifyEvent::ePanHorizontal;
3609 }
3610 if (treeFrame->GetVerticalOverflow()) {
3611 panDirection = WidgetGestureNotifyEvent::ePanVertical;
3612 }
3613 break;
3614 }
3615
3616 if (ScrollContainerFrame* scrollContainerFrame = do_QueryFrame(current)) {
3617 layers::ScrollDirections scrollbarVisibility =
3618 scrollContainerFrame->GetScrollbarVisibility();
3619
3620 // Check if we have visible scrollbars
3621 if (scrollbarVisibility.contains(layers::ScrollDirection::eVertical)) {
3622 panDirection = WidgetGestureNotifyEvent::ePanVertical;
3623 displayPanFeedback = true;
3624 break;
3625 }
3626
3627 if (scrollbarVisibility.contains(layers::ScrollDirection::eHorizontal)) {
3628 panDirection = WidgetGestureNotifyEvent::ePanHorizontal;
3629 displayPanFeedback = true;
3630 }
3631 }
3632 } // ancestor chain
3633 aEvent->mDisplayPanFeedback = displayPanFeedback;
3634 aEvent->mPanDirection = panDirection;
3635}
3636
3637#ifdef XP_MACOSX
3638static nsINode* GetCrossDocParentNode(nsINode* aChild) {
3639 MOZ_ASSERT(aChild, "The child is null!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChild)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aChild))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aChild" " (" "The child is null!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3639); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild" ") ("
"The child is null!" ")"); do { *((volatile int*)__null) = 3639
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
3640 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3640); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 3640; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3641
3642 nsINode* parent = aChild->GetParentNode();
3643 if (parent && parent->IsContent() && aChild->IsContent()) {
3644 parent = aChild->AsContent()->GetFlattenedTreeParent();
3645 }
3646
3647 if (parent || !aChild->IsDocument()) {
3648 return parent;
3649 }
3650
3651 return aChild->AsDocument()->GetEmbedderElement();
3652}
3653
3654static bool NodeAllowsClickThrough(nsINode* aNode) {
3655 while (aNode) {
3656 if (aNode->IsAnyOfXULElements(nsGkAtoms::browser, nsGkAtoms::tree)) {
3657 return false;
3658 }
3659 if (aNode->IsAnyOfXULElements(nsGkAtoms::scrollbar, nsGkAtoms::resizer)) {
3660 return true;
3661 }
3662 aNode = GetCrossDocParentNode(aNode);
3663 }
3664 return true;
3665}
3666#endif
3667
3668void EventStateManager::PostHandleKeyboardEvent(
3669 WidgetKeyboardEvent* aKeyboardEvent, nsIFrame* aTargetFrame,
3670 nsEventStatus& aStatus) {
3671 if (aStatus == nsEventStatus_eConsumeNoDefault) {
3672 return;
3673 }
3674
3675 RefPtr<nsPresContext> presContext = mPresContext;
3676
3677 if (!aKeyboardEvent->HasBeenPostedToRemoteProcess()) {
3678 if (aKeyboardEvent->IsWaitingReplyFromRemoteProcess()) {
3679 RefPtr<BrowserParent> remote =
3680 aTargetFrame ? BrowserParent::GetFrom(aTargetFrame->GetContent())
3681 : nullptr;
3682 if (remote) {
3683 // remote is null-checked above in order to let pre-existing event
3684 // targeting code's chrome vs. content decision override in case of
3685 // disagreement in order not to disrupt non-Fission e10s mode in case
3686 // there are still bugs in the Fission-mode code. That is, if remote
3687 // is nullptr, the pre-existing event targeting code has deemed this
3688 // event to belong to chrome rather than content.
3689 BrowserParent* preciseRemote = BrowserParent::GetFocused();
3690 if (preciseRemote) {
3691 remote = preciseRemote;
3692 }
3693 // else there was a race between layout and focus tracking
3694 }
3695 if (remote && !remote->IsReadyToHandleInputEvents()) {
3696 // We need to dispatch the event to the browser element again if we were
3697 // waiting for the key reply but the event wasn't sent to the content
3698 // process due to the remote browser wasn't ready.
3699 WidgetKeyboardEvent keyEvent(*aKeyboardEvent);
3700 aKeyboardEvent->MarkAsHandledInRemoteProcess();
3701 RefPtr<Element> ownerElement = remote->GetOwnerElement();
3702 EventDispatcher::Dispatch(ownerElement, presContext, &keyEvent);
3703 if (keyEvent.DefaultPrevented()) {
3704 aKeyboardEvent->PreventDefault(!keyEvent.DefaultPreventedByContent());
3705 aStatus = nsEventStatus_eConsumeNoDefault;
3706 return;
3707 }
3708 }
3709 }
3710 // The widget expects a reply for every keyboard event. If the event wasn't
3711 // dispatched to a content process (non-e10s or no content process
3712 // running), we need to short-circuit here. Otherwise, we need to wait for
3713 // the content process to handle the event.
3714 if (aKeyboardEvent->mWidget) {
3715 aKeyboardEvent->mWidget->PostHandleKeyEvent(aKeyboardEvent);
3716 }
3717 if (aKeyboardEvent->DefaultPrevented()) {
3718 aStatus = nsEventStatus_eConsumeNoDefault;
3719 return;
3720 }
3721 }
3722
3723 // XXX Currently, our automated tests don't support mKeyNameIndex.
3724 // Therefore, we still need to handle this with keyCode.
3725 switch (aKeyboardEvent->mKeyCode) {
3726 case NS_VK_TAB:
3727 case NS_VK_F6:
3728 // This is to prevent keyboard scrolling while alt modifier in use.
3729 if (!aKeyboardEvent->IsAlt()) {
3730 aStatus = nsEventStatus_eConsumeNoDefault;
3731
3732 // Handling the tab event after it was sent to content is bad,
3733 // because to the FocusManager the remote-browser looks like one
3734 // element, so we would just move the focus to the next element
3735 // in chrome, instead of handling it in content.
3736 if (aKeyboardEvent->HasBeenPostedToRemoteProcess()) {
3737 break;
3738 }
3739
3740 EnsureDocument(presContext);
3741 nsFocusManager* fm = nsFocusManager::GetFocusManager();
3742 if (fm && mDocument) {
3743 // Shift focus forward or back depending on shift key
3744 bool isDocMove = aKeyboardEvent->IsControl() ||
3745 aKeyboardEvent->mKeyCode == NS_VK_F6;
3746 uint32_t dir =
3747 aKeyboardEvent->IsShift()
3748 ? (isDocMove ? static_cast<uint32_t>(
3749 nsIFocusManager::MOVEFOCUS_BACKWARDDOC)
3750 : static_cast<uint32_t>(
3751 nsIFocusManager::MOVEFOCUS_BACKWARD))
3752 : (isDocMove ? static_cast<uint32_t>(
3753 nsIFocusManager::MOVEFOCUS_FORWARDDOC)
3754 : static_cast<uint32_t>(
3755 nsIFocusManager::MOVEFOCUS_FORWARD));
3756 RefPtr<Element> result;
3757 fm->MoveFocus(mDocument->GetWindow(), nullptr, dir,
3758 nsIFocusManager::FLAG_BYKEY, getter_AddRefs(result));
3759 }
3760 }
3761 return;
3762 case 0:
3763 // We handle keys with no specific keycode value below.
3764 break;
3765 default:
3766 return;
3767 }
3768
3769 switch (aKeyboardEvent->mKeyNameIndex) {
3770 case KEY_NAME_INDEX_ZoomIn:
3771 case KEY_NAME_INDEX_ZoomOut:
3772 ChangeZoom(aKeyboardEvent->mKeyNameIndex == KEY_NAME_INDEX_ZoomIn);
3773 aStatus = nsEventStatus_eConsumeNoDefault;
3774 break;
3775 default:
3776 break;
3777 }
3778}
3779
3780static bool NeedsActiveContentChange(const WidgetMouseEvent* aMouseEvent) {
3781 // If the mouse event is a synthesized mouse event due to a touch, do
3782 // not set/clear the activation state. Element activation is handled by APZ.
3783 return !aMouseEvent ||
3784 aMouseEvent->mInputSource != MouseEvent_Binding::MOZ_SOURCE_TOUCH;
3785}
3786
3787nsresult EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
3788 WidgetEvent* aEvent,
3789 nsIFrame* aTargetFrame,
3790 nsEventStatus* aStatus,
3791 nsIContent* aOverrideClickTarget) {
3792 AUTO_PROFILER_LABEL("EventStateManager::PostHandleEvent", DOM)mozilla::AutoProfilerLabel raiiObject3792( "EventStateManager::PostHandleEvent"
, nullptr, JS::ProfilingCategoryPair::DOM)
;
3793 NS_ENSURE_ARG(aPresContext)do { if ((__builtin_expect(!!(!(aPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3793); return NS_ERROR_INVALID_ARG; } } while (false)
;
1
Assuming 'aPresContext' is non-null
2
Taking false branch
3
Loop condition is false. Exiting loop
3794 NS_ENSURE_ARG_POINTER(aStatus)do { if ((__builtin_expect(!!(!(aStatus)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStatus" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3794); return NS_ERROR_INVALID_POINTER; } } while (false)
;
4
Assuming 'aStatus' is non-null
5
Taking false branch
6
Loop condition is false. Exiting loop
3795
3796 mCurrentTarget = aTargetFrame;
3797 mCurrentTargetContent = nullptr;
3798
3799 HandleCrossProcessEvent(aEvent, aStatus);
3800 // NOTE: the above call may have destroyed aTargetFrame, please use
3801 // mCurrentTarget henceforth. This is to avoid using it accidentally:
3802 aTargetFrame = nullptr;
3803
3804 // Most of the events we handle below require a frame.
3805 // Add special cases here.
3806 if (!mCurrentTarget && aEvent->mMessage != eMouseUp &&
7
Assuming the condition is false
3807 aEvent->mMessage != eMouseDown && aEvent->mMessage != eDragEnter &&
3808 aEvent->mMessage != eDragOver && aEvent->mMessage != ePointerUp &&
3809 aEvent->mMessage != ePointerCancel) {
3810 return NS_OK;
3811 }
3812
3813 // Keep the prescontext alive, we might need it after event dispatch
3814 RefPtr<nsPresContext> presContext = aPresContext;
3815 nsresult ret = NS_OK;
3816
3817 switch (aEvent->mMessage) {
8
Control jumps to 'case ePointerUp:' at line 4034
3818 case eMouseDown: {
3819 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
3820 if (mouseEvent->mButton == MouseButton::ePrimary &&
3821 !sNormalLMouseEventInProcess) {
3822 // We got a mouseup event while a mousedown event was being processed.
3823 // Make sure that the capturing content is cleared.
3824 PresShell::ReleaseCapturingContent();
3825 break;
3826 }
3827
3828 // For remote content, capture the event in the parent process at the
3829 // <xul:browser remote> element. This will ensure that subsequent
3830 // mousemove/mouseup events will continue to be dispatched to this element
3831 // and therefore forwarded to the child.
3832 if (aEvent->HasBeenPostedToRemoteProcess() &&
3833 !PresShell::GetCapturingContent()) {
3834 if (nsIContent* content =
3835 mCurrentTarget ? mCurrentTarget->GetContent() : nullptr) {
3836 PresShell::SetCapturingContent(content, CaptureFlags::None, aEvent);
3837 } else {
3838 PresShell::ReleaseCapturingContent();
3839 }
3840 }
3841
3842 // If MouseEvent::PreventClickEvent() was called by chrome script,
3843 // we need to forget the clicking content and click count for the
3844 // following eMouseUp event.
3845 if (mouseEvent->mClickEventPrevented) {
3846 switch (mouseEvent->mButton) {
3847 case MouseButton::ePrimary:
3848 case MouseButton::eSecondary:
3849 case MouseButton::eMiddle: {
3850 LastMouseDownInfo& mouseDownInfo =
3851 GetLastMouseDownInfo(mouseEvent->mButton);
3852 mouseDownInfo.mLastMouseDownContent = nullptr;
3853 mouseDownInfo.mClickCount = 0;
3854 mouseDownInfo.mLastMouseDownInputControlType = Nothing();
3855 break;
3856 }
3857
3858 default:
3859 break;
3860 }
3861 }
3862
3863 nsCOMPtr<nsIContent> activeContent;
3864 // When content calls PreventDefault on pointerdown, we also call
3865 // PreventDefault on the subsequent mouse events to suppress default
3866 // behaviors. Normally, aStatus should be nsEventStatus_eConsumeNoDefault
3867 // when the event is DefaultPrevented but it's reset to
3868 // nsEventStatus_eIgnore in EventStateManager::PreHandleEvent. So we also
3869 // check if the event is DefaultPrevented.
3870 if (nsEventStatus_eConsumeNoDefault != *aStatus &&
3871 !aEvent->DefaultPrevented()) {
3872 nsCOMPtr<nsIContent> newFocus;
3873 bool suppressBlur = false;
3874 if (mCurrentTarget) {
3875 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(newFocus));
3876 activeContent = mCurrentTarget->GetContent();
3877
3878 // In some cases, we do not want to even blur the current focused
3879 // element. Those cases are:
3880 // 1. -moz-user-focus CSS property is set to 'ignore';
3881 // 2. XUL control element has the disabled property set to 'true'.
3882 //
3883 // We can't use nsIFrame::IsFocusable() because we want to blur when
3884 // we click on a visibility: none element.
3885 // We can't use nsIContent::IsFocusable() because we want to blur when
3886 // we click on a non-focusable element like a <div>.
3887 // We have to use |aEvent->mTarget| to not make sure we do not check
3888 // an anonymous node of the targeted element.
3889 suppressBlur =
3890 mCurrentTarget->StyleUI()->UserFocus() == StyleUserFocus::Ignore;
3891
3892 if (!suppressBlur) {
3893 if (Element* element =
3894 Element::FromEventTargetOrNull(aEvent->mTarget)) {
3895 if (nsCOMPtr<nsIDOMXULControlElement> xulControl =
3896 element->AsXULControl()) {
3897 bool disabled = false;
3898 xulControl->GetDisabled(&disabled);
3899 suppressBlur = disabled;
3900 }
3901 }
3902 }
3903 }
3904
3905 // When a root content which isn't editable but has an editable HTML
3906 // <body> element is clicked, we should redirect the focus to the
3907 // the <body> element. E.g., when an user click bottom of the editor
3908 // where is outside of the <body> element, the <body> should be focused
3909 // and the user can edit immediately after that.
3910 //
3911 // NOTE: The newFocus isn't editable that also means it's not in
3912 // designMode. In designMode, all contents are not focusable.
3913 if (newFocus && !newFocus->IsEditable()) {
3914 Document* doc = newFocus->GetComposedDoc();
3915 if (doc && newFocus == doc->GetRootElement()) {
3916 nsIContent* bodyContent =
3917 nsLayoutUtils::GetEditableRootContentByContentEditable(doc);
3918 if (bodyContent && bodyContent->GetPrimaryFrame()) {
3919 newFocus = bodyContent;
3920 }
3921 }
3922 }
3923
3924 // When the mouse is pressed, the default action is to focus the
3925 // target. Look for the nearest enclosing focusable frame.
3926 //
3927 // TODO: Probably this should be moved to Element::PostHandleEvent.
3928 for (; newFocus; newFocus = newFocus->GetFlattenedTreeParent()) {
3929 if (!newFocus->IsElement()) {
3930 continue;
3931 }
3932
3933 nsIFrame* frame = newFocus->GetPrimaryFrame();
3934 if (!frame) {
3935 continue;
3936 }
3937
3938 // If the mousedown happened inside a popup, don't try to set focus on
3939 // one of its containing elements
3940 if (frame->IsMenuPopupFrame()) {
3941 newFocus = nullptr;
3942 break;
3943 }
3944
3945 auto flags = IsFocusableFlags::WithMouse;
3946 if (frame->IsFocusable(flags)) {
3947 break;
3948 }
3949
3950 if (ShadowRoot* root = newFocus->GetShadowRoot()) {
3951 if (root->DelegatesFocus()) {
3952 if (Element* firstFocusable = root->GetFocusDelegate(flags)) {
3953 newFocus = firstFocusable;
3954 break;
3955 }
3956 }
3957 }
3958 }
3959
3960 MOZ_ASSERT_IF(newFocus, newFocus->IsElement())do { if (newFocus) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(newFocus->IsElement())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(newFocus->IsElement()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("newFocus->IsElement()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3960); AnnotateMozCrashReason("MOZ_ASSERT" "(" "newFocus->IsElement()"
")"); do { *((volatile int*)__null) = 3960; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
3961
3962 if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
3963 // if something was found to focus, focus it. Otherwise, if the
3964 // element that was clicked doesn't have -moz-user-focus: ignore,
3965 // clear the existing focus. For -moz-user-focus: ignore, the focus
3966 // is just left as is.
3967 // Another effect of mouse clicking, handled in Selection, is that
3968 // it should update the caret position to where the mouse was
3969 // clicked. Because the focus is cleared when clicking on a
3970 // non-focusable node, the next press of the tab key will cause
3971 // focus to be shifted from the caret position instead of the root.
3972 if (newFocus) {
3973 // use the mouse flag and the noscroll flag so that the content
3974 // doesn't unexpectedly scroll when clicking an element that is
3975 // only half visible
3976 uint32_t flags =
3977 nsIFocusManager::FLAG_BYMOUSE | nsIFocusManager::FLAG_NOSCROLL;
3978 // If this was a touch-generated event, pass that information:
3979 if (mouseEvent->mInputSource ==
3980 MouseEvent_Binding::MOZ_SOURCE_TOUCH) {
3981 flags |= nsIFocusManager::FLAG_BYTOUCH;
3982 }
3983 fm->SetFocus(MOZ_KnownLive(newFocus->AsElement())(newFocus->AsElement()), flags);
3984 } else if (!suppressBlur) {
3985 // clear the focus within the frame and then set it as the
3986 // focused frame
3987 EnsureDocument(mPresContext);
3988 if (mDocument) {
3989 nsCOMPtr<nsPIDOMWindowOuter> outerWindow = mDocument->GetWindow();
3990#ifdef XP_MACOSX
3991 if (!activeContent || !activeContent->IsXULElement())
3992#endif
3993 fm->ClearFocus(outerWindow);
3994 // Prevent switch frame if we're already not in the foreground tab
3995 // and we're in a content process.
3996 // TODO: If we were inactive frame in this tab, and now in
3997 // background tab, we shouldn't make the tab foreground, but
3998 // we should set focus to clicked document in the background
3999 // tab. However, nsFocusManager does not have proper method
4000 // for doing this. Therefore, we should skip setting focus
4001 // to clicked document for now.
4002 if (XRE_IsParentProcess() || IsInActiveTab(mDocument)) {
4003 fm->SetFocusedWindow(outerWindow);
4004 }
4005 }
4006 }
4007 }
4008
4009 // The rest is left button-specific.
4010 if (mouseEvent->mButton != MouseButton::ePrimary) {
4011 break;
4012 }
4013
4014 // The nearest enclosing element goes into the :active state. If we're
4015 // not an element (so we're text or something) we need to obtain
4016 // our parent element and put it into :active instead.
4017 if (activeContent && !activeContent->IsElement()) {
4018 if (nsIContent* par = activeContent->GetFlattenedTreeParent()) {
4019 activeContent = par;
4020 }
4021 }
4022 } else {
4023 // if we're here, the event handler returned false, so stop
4024 // any of our own processing of a drag. Workaround for bug 43258.
4025 StopTrackingDragGesture(true);
4026 }
4027 // XXX Why do we always set this is active? Active window may be changed
4028 // by a mousedown event listener.
4029 if (NeedsActiveContentChange(mouseEvent)) {
4030 SetActiveManager(this, activeContent);
4031 }
4032 } break;
4033 case ePointerCancel:
4034 case ePointerUp: {
4035 WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent();
4036 MOZ_ASSERT(pointerEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(pointerEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pointerEvent))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("pointerEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4036); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pointerEvent"
")"); do { *((volatile int*)__null) = 4036; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9
Assuming 'pointerEvent' is non-null
10
Taking false branch
11
Loop condition is false. Exiting loop
4037 // Implicitly releasing capture for given pointer. ePointerLostCapture
4038 // should be send after ePointerUp or ePointerCancel.
4039 PointerEventHandler::ImplicitlyReleasePointerCapture(pointerEvent);
4040 PointerEventHandler::UpdateActivePointerState(pointerEvent);
4041
4042 if (
14
Taking true branch
4043 // After pointercancel, pointer becomes invalid so we can remove
4044 // relevant helper from table.
4045 pointerEvent->mMessage == ePointerCancel ||
12
Assuming field 'mMessage' is not equal to ePointerCancel
4046 // pointerup for non-hoverable pointer needs to dispatch pointerout
4047 // and pointerleave events because the pointer is valid only while the
4048 // pointer is "down".
4049 !pointerEvent->InputSourceSupportsHover()) {
13
Assuming the condition is true
4050 GenerateMouseEnterExit(pointerEvent);
15
Calling 'EventStateManager::GenerateMouseEnterExit'
4051 mPointersEnterLeaveHelper.Remove(pointerEvent->pointerId);
4052 }
4053
4054 break;
4055 }
4056 case eMouseUp: {
4057 // We can unconditionally stop capturing because
4058 // we should never be capturing when the mouse button is up
4059 PresShell::ReleaseCapturingContent();
4060
4061 WidgetMouseEvent* mouseUpEvent = aEvent->AsMouseEvent();
4062 if (NeedsActiveContentChange(mouseUpEvent)) {
4063 ClearGlobalActiveContent(this);
4064 }
4065 if (mouseUpEvent && EventCausesClickEvents(*mouseUpEvent)) {
4066 // Make sure to dispatch the click even if there is no frame for
4067 // the current target element. This is required for Web compatibility.
4068 RefPtr<EventStateManager> esm =
4069 ESMFromContentOrThis(aOverrideClickTarget);
4070 ret =
4071 esm->PostHandleMouseUp(mouseUpEvent, aStatus, aOverrideClickTarget);
4072 }
4073
4074 if (PresShell* presShell = presContext->GetPresShell()) {
4075 RefPtr<nsFrameSelection> frameSelection = presShell->FrameSelection();
4076 frameSelection->SetDragState(false);
4077 }
4078 } break;
4079 case eWheelOperationEnd: {
4080 MOZ_ASSERT(aEvent->IsTrusted())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->IsTrusted())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->IsTrusted()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->IsTrusted()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4080); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsTrusted()"
")"); do { *((volatile int*)__null) = 4080; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4081 ScrollbarsForWheel::MayInactivate();
4082 WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
4083 ScrollContainerFrame* scrollTarget =
4084 ComputeScrollTargetAndMayAdjustWheelEvent(
4085 mCurrentTarget, wheelEvent,
4086 COMPUTE_DEFAULT_ACTION_TARGET_WITH_AUTO_DIR);
4087 // If the wheel event was handled by APZ, APZ will perform the scroll
4088 // snap.
4089 if (scrollTarget && !WheelTransaction::HandledByApz()) {
4090 scrollTarget->ScrollSnap();
4091 }
4092 } break;
4093 case eWheel:
4094 case eWheelOperationStart: {
4095 MOZ_ASSERT(aEvent->IsTrusted())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->IsTrusted())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->IsTrusted()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->IsTrusted()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4095); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsTrusted()"
")"); do { *((volatile int*)__null) = 4095; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4096
4097 if (*aStatus == nsEventStatus_eConsumeNoDefault) {
4098 ScrollbarsForWheel::Inactivate();
4099 break;
4100 }
4101
4102 WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
4103 MOZ_ASSERT(wheelEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(wheelEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(wheelEvent))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("wheelEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4103); AnnotateMozCrashReason("MOZ_ASSERT" "(" "wheelEvent"
")"); do { *((volatile int*)__null) = 4103; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4104
4105 // When APZ is enabled, the actual scroll animation might be handled by
4106 // the compositor.
4107 WheelPrefs::Action action =
4108 wheelEvent->mFlags.mHandledByAPZ
4109 ? WheelPrefs::ACTION_NONE
4110 : WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent);
4111
4112 WheelDeltaAdjustmentStrategy strategy =
4113 GetWheelDeltaAdjustmentStrategy(*wheelEvent);
4114 // Adjust the delta values of the wheel event if the current default
4115 // action is to horizontalize scrolling. I.e., deltaY values are set to
4116 // deltaX and deltaY and deltaZ values are set to 0.
4117 // If horizontalized, the delta values will be restored and its overflow
4118 // deltaX will become 0 when the WheelDeltaHorizontalizer instance is
4119 // being destroyed.
4120 WheelDeltaHorizontalizer horizontalizer(*wheelEvent);
4121 if (WheelDeltaAdjustmentStrategy::eHorizontalize == strategy) {
4122 horizontalizer.Horizontalize();
4123 }
4124
4125 // Since ComputeScrollTargetAndMayAdjustWheelEvent() may adjust the delta
4126 // if the event is auto-dir. So we use |ESMAutoDirWheelDeltaRestorer|
4127 // here.
4128 // An instance of |ESMAutoDirWheelDeltaRestorer| is used to monitor
4129 // auto-dir adjustment which may happen during its lifetime. If the delta
4130 // values is adjusted during its lifetime, the instance will restore the
4131 // adjusted delta when it's being destrcuted.
4132 ESMAutoDirWheelDeltaRestorer restorer(*wheelEvent);
4133 ScrollContainerFrame* scrollTarget =
4134 ComputeScrollTargetAndMayAdjustWheelEvent(
4135 mCurrentTarget, wheelEvent,
4136 COMPUTE_DEFAULT_ACTION_TARGET_WITH_AUTO_DIR);
4137
4138 switch (action) {
4139 case WheelPrefs::ACTION_SCROLL:
4140 case WheelPrefs::ACTION_HORIZONTALIZED_SCROLL: {
4141 // For scrolling of default action, we should honor the mouse wheel
4142 // transaction.
4143
4144 ScrollbarsForWheel::PrepareToScrollText(this, mCurrentTarget,
4145 wheelEvent);
4146
4147 if (aEvent->mMessage != eWheel ||
4148 (!wheelEvent->mDeltaX && !wheelEvent->mDeltaY)) {
4149 break;
4150 }
4151
4152 ScrollbarsForWheel::SetActiveScrollTarget(scrollTarget);
4153
4154 ScrollContainerFrame* rootScrollContainerFrame =
4155 !mCurrentTarget
4156 ? nullptr
4157 : mCurrentTarget->PresShell()->GetRootScrollContainerFrame();
4158 if (!scrollTarget || scrollTarget == rootScrollContainerFrame) {
4159 wheelEvent->mViewPortIsOverscrolled = true;
4160 }
4161 wheelEvent->mOverflowDeltaX = wheelEvent->mDeltaX;
4162 wheelEvent->mOverflowDeltaY = wheelEvent->mDeltaY;
4163 WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(
4164 wheelEvent);
4165 if (scrollTarget) {
4166 DoScrollText(scrollTarget, wheelEvent);
4167 } else {
4168 WheelTransaction::EndTransaction();
4169 ScrollbarsForWheel::Inactivate();
4170 }
4171 break;
4172 }
4173 case WheelPrefs::ACTION_HISTORY: {
4174 // If this event doesn't cause eLegacyMouseLineOrPageScroll event or
4175 // the direction is oblique, don't perform history back/forward.
4176 int32_t intDelta = wheelEvent->GetPreferredIntDelta();
4177 if (!intDelta) {
4178 break;
4179 }
4180 DoScrollHistory(intDelta);
4181 break;
4182 }
4183 case WheelPrefs::ACTION_ZOOM: {
4184 // If this event doesn't cause eLegacyMouseLineOrPageScroll event or
4185 // the direction is oblique, don't perform zoom in/out.
4186 int32_t intDelta = wheelEvent->GetPreferredIntDelta();
4187 if (!intDelta) {
4188 break;
4189 }
4190 DoScrollZoom(mCurrentTarget, intDelta);
4191 break;
4192 }
4193 case WheelPrefs::ACTION_NONE:
4194 default:
4195 bool allDeltaOverflown = false;
4196 if (StaticPrefs::dom_event_wheel_event_groups_enabled() &&
4197 (wheelEvent->mDeltaX != 0.0 || wheelEvent->mDeltaY != 0.0)) {
4198 if (scrollTarget) {
4199 WheelTransaction::WillHandleDefaultAction(
4200 wheelEvent, scrollTarget, mCurrentTarget);
4201 } else {
4202 WheelTransaction::EndTransaction();
4203 }
4204 }
4205 if (wheelEvent->mFlags.mHandledByAPZ) {
4206 if (wheelEvent->mCanTriggerSwipe) {
4207 // For events that can trigger swipes, APZ needs to know whether
4208 // scrolling is possible in the requested direction. It does this
4209 // by looking at the scroll overflow values on mCanTriggerSwipe
4210 // events after they have been processed.
4211 allDeltaOverflown = !ComputeScrollTarget(
4212 mCurrentTarget, wheelEvent, COMPUTE_DEFAULT_ACTION_TARGET);
4213 }
4214 } else {
4215 // The event was processed neither by APZ nor by us, so all of the
4216 // delta values must be overflown delta values.
4217 allDeltaOverflown = true;
4218 }
4219
4220 if (!allDeltaOverflown) {
4221 break;
4222 }
4223 wheelEvent->mOverflowDeltaX = wheelEvent->mDeltaX;
4224 wheelEvent->mOverflowDeltaY = wheelEvent->mDeltaY;
4225 WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(
4226 wheelEvent);
4227 wheelEvent->mViewPortIsOverscrolled = true;
4228 break;
4229 }
4230 *aStatus = nsEventStatus_eConsumeNoDefault;
4231 } break;
4232
4233 case eGestureNotify: {
4234 if (nsEventStatus_eConsumeNoDefault != *aStatus) {
4235 DecideGestureEvent(aEvent->AsGestureNotifyEvent(), mCurrentTarget);
4236 }
4237 } break;
4238
4239 case eDragEnter:
4240 case eDragOver: {
4241 NS_ASSERTION(aEvent->mClass == eDragEventClass, "Expected a drag event")do { if (!(aEvent->mClass == eDragEventClass)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Expected a drag event", "aEvent->mClass == eDragEventClass"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4241); MOZ_PretendNoReturn(); } } while (0)
;
4242
4243 // Check if the drag is occurring inside a scrollable area. If so, scroll
4244 // the area when the mouse is near the edges.
4245 if (mCurrentTarget && aEvent->mMessage == eDragOver) {
4246 nsIFrame* checkFrame = mCurrentTarget;
4247 while (checkFrame) {
4248 ScrollContainerFrame* scrollFrame = do_QueryFrame(checkFrame);
4249 // Break out so only the innermost scrollframe is scrolled.
4250 if (scrollFrame && scrollFrame->DragScroll(aEvent)) {
4251 break;
4252 }
4253 checkFrame = checkFrame->GetParent();
4254 }
4255 }
4256
4257 nsCOMPtr<nsIDragSession> dragSession =
4258 nsContentUtils::GetDragSession(mPresContext);
4259 if (!dragSession) break;
4260
4261 // Reset the flag.
4262 dragSession->SetOnlyChromeDrop(false);
4263 if (mPresContext) {
4264 EnsureDocument(mPresContext);
4265 }
4266 bool isChromeDoc = nsContentUtils::IsChromeDoc(mDocument);
4267
4268 // the initial dataTransfer is the one from the dragstart event that
4269 // was set on the dragSession when the drag began.
4270 RefPtr<DataTransfer> dataTransfer;
4271 RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer();
4272
4273 WidgetDragEvent* dragEvent = aEvent->AsDragEvent();
4274
4275 // collect any changes to moz cursor settings stored in the event's
4276 // data transfer.
4277 UpdateDragDataTransfer(dragEvent);
4278
4279 // cancelling a dragenter or dragover event means that a drop should be
4280 // allowed, so update the dropEffect and the canDrop state to indicate
4281 // that a drag is allowed. If the event isn't cancelled, a drop won't be
4282 // allowed. Essentially, to allow a drop somewhere, specify the effects
4283 // using the effectAllowed and dropEffect properties in a dragenter or
4284 // dragover event and cancel the event. To not allow a drop somewhere,
4285 // don't cancel the event or set the effectAllowed or dropEffect to
4286 // "none". This way, if the event is just ignored, no drop will be
4287 // allowed.
4288 uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
4289 uint32_t action = nsIDragService::DRAGDROP_ACTION_NONE;
4290 if (nsEventStatus_eConsumeNoDefault == *aStatus) {
4291 // If the event has initialized its mDataTransfer, use it.
4292 // Or the event has not been initialized its mDataTransfer, but
4293 // it's set before dispatch because of synthesized, but without
4294 // testing session (e.g., emulating drag from another app), use it
4295 // coming from outside.
4296 // XXX Perhaps, for the latter case, we need new API because we don't
4297 // have a chance to initialize allowed effects of the session.
4298 if (dragEvent->mDataTransfer) {
4299 // get the dataTransfer and the dropEffect that was set on it
4300 dataTransfer = dragEvent->mDataTransfer;
4301 dropEffect = dataTransfer->DropEffectInt();
4302 } else {
4303 // if dragEvent->mDataTransfer is null, it means that no attempt was
4304 // made to access the dataTransfer during the event, yet the event
4305 // was cancelled. Instead, use the initial data transfer available
4306 // from the drag session. The drop effect would not have been
4307 // initialized (which is done in DragEvent::GetDataTransfer),
4308 // so set it from the drag action. We'll still want to filter it
4309 // based on the effectAllowed below.
4310 dataTransfer = initialDataTransfer;
4311
4312 dragSession->GetDragAction(&action);
4313
4314 // filter the drop effect based on the action. Use UNINITIALIZED as
4315 // any effect is allowed.
4316 dropEffect = nsContentUtils::FilterDropEffect(
4317 action, nsIDragService::DRAGDROP_ACTION_UNINITIALIZED);
4318 }
4319
4320 // At this point, if the dataTransfer is null, it means that the
4321 // drag was originally started by directly calling the drag service.
4322 // Just assume that all effects are allowed.
4323 uint32_t effectAllowed = nsIDragService::DRAGDROP_ACTION_UNINITIALIZED;
4324 if (dataTransfer) {
4325 effectAllowed = dataTransfer->EffectAllowedInt();
4326 }
4327
4328 // set the drag action based on the drop effect and effect allowed.
4329 // The drop effect field on the drag transfer object specifies the
4330 // desired current drop effect. However, it cannot be used if the
4331 // effectAllowed state doesn't include that type of action. If the
4332 // dropEffect is "none", then the action will be 'none' so a drop will
4333 // not be allowed.
4334 if (effectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED ||
4335 dropEffect & effectAllowed)
4336 action = dropEffect;
4337
4338 if (action == nsIDragService::DRAGDROP_ACTION_NONE)
4339 dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
4340
4341 // inform the drag session that a drop is allowed on this node.
4342 dragSession->SetDragAction(action);
4343 dragSession->SetCanDrop(action != nsIDragService::DRAGDROP_ACTION_NONE);
4344
4345 // For now, do this only for dragover.
4346 // XXXsmaug dragenter needs some more work.
4347 if (aEvent->mMessage == eDragOver && !isChromeDoc) {
4348 // Someone has called preventDefault(), check whether is was on
4349 // content or chrome.
4350 dragSession->SetOnlyChromeDrop(
4351 !dragEvent->mDefaultPreventedOnContent);
4352 }
4353 } else if (aEvent->mMessage == eDragOver && !isChromeDoc) {
4354 // No one called preventDefault(), so handle drop only in chrome.
4355 dragSession->SetOnlyChromeDrop(true);
4356 }
4357 if (auto* bc = BrowserChild::GetFrom(presContext->GetDocShell())) {
4358 bc->SendUpdateDropEffect(action, dropEffect);
4359 }
4360 if (aEvent->HasBeenPostedToRemoteProcess()) {
4361 dragSession->SetCanDrop(true);
4362 } else if (initialDataTransfer) {
4363 // Now set the drop effect in the initial dataTransfer. This ensures
4364 // that we can get the desired drop effect in the drop event. For events
4365 // dispatched to content, the content process will take care of setting
4366 // this.
4367 initialDataTransfer->SetDropEffectInt(dropEffect);
4368 }
4369 } break;
4370
4371 case eDrop: {
4372 if (aEvent->mFlags.mIsSynthesizedForTests) {
4373 nsCOMPtr<nsIDragService> dragService =
4374 do_GetService("@mozilla.org/widget/dragservice;1");
4375 nsCOMPtr<nsIDragSession> dragSession =
4376 nsContentUtils::GetDragSession(mPresContext);
4377 if (dragSession && dragService &&
4378 !dragService->GetNeverAllowSessionIsSynthesizedForTests()) {
4379 MOZ_ASSERT(dragSession->IsSynthesizedForTests())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(dragSession->IsSynthesizedForTests())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(dragSession->IsSynthesizedForTests()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("dragSession->IsSynthesizedForTests()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4379); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dragSession->IsSynthesizedForTests()"
")"); do { *((volatile int*)__null) = 4379; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4380 RefPtr<WindowContext> sourceWC;
4381 DebugOnly<nsresult> rvIgnored =
4382 dragSession->GetSourceWindowContext(getter_AddRefs(sourceWC));
4383 NS_WARNING_ASSERTION(do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "nsIDragSession::GetSourceDocument() failed, but ignored"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4385); } } while (false)
4384 NS_SUCCEEDED(rvIgnored),do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "nsIDragSession::GetSourceDocument() failed, but ignored"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4385); } } while (false)
4385 "nsIDragSession::GetSourceDocument() failed, but ignored")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "nsIDragSession::GetSourceDocument() failed, but ignored"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4385); } } while (false)
;
4386 // If the drag source hasn't been initialized, i.e., dragstart was
4387 // consumed by the test, the test needs to dispatch "dragend" event
4388 // instead of the drag session. Therefore, it does not make sense
4389 // to set drag end point in such case (you hit assersion if you do
4390 // it).
4391 if (sourceWC) {
4392 CSSIntPoint dropPointInScreen =
4393 Event::GetScreenCoords(aPresContext, aEvent, aEvent->mRefPoint)
4394 .extract();
4395 dragSession->SetDragEndPointForTests(dropPointInScreen.x,
4396 dropPointInScreen.y);
4397 }
4398 }
4399 }
4400 sLastDragOverFrame = nullptr;
4401 ClearGlobalActiveContent(this);
4402 break;
4403 }
4404 case eDragExit: {
4405 // make sure to fire the enter and exit_synth events after the
4406 // eDragExit event, otherwise we'll clean up too early
4407 GenerateDragDropEnterExit(presContext, aEvent->AsDragEvent());
4408 if (auto* bc = BrowserChild::GetFrom(presContext->GetDocShell())) {
4409 // SendUpdateDropEffect to prevent nsIDragService from waiting for
4410 // response of forwarded dragexit event.
4411 bc->SendUpdateDropEffect(nsIDragService::DRAGDROP_ACTION_NONE,
4412 nsIDragService::DRAGDROP_ACTION_NONE);
4413 }
4414 break;
4415 }
4416 case eKeyUp:
4417 // If space key is released, we need to inactivate the element which was
4418 // activated by preceding space key down.
4419 // XXX Currently, we don't store the reason of activation. Therefore,
4420 // this may cancel what is activated by a mousedown, but it must not
4421 // cause actual problem in web apps in the wild since it must be
4422 // rare case that users release space key during a mouse click/drag.
4423 if (aEvent->AsKeyboardEvent()->ShouldWorkAsSpaceKey()) {
4424 ClearGlobalActiveContent(this);
4425 }
4426 break;
4427
4428 case eKeyPress: {
4429 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
4430 PostHandleKeyboardEvent(keyEvent, mCurrentTarget, *aStatus);
4431 } break;
4432
4433 case eMouseEnterIntoWidget:
4434 if (mCurrentTarget) {
4435 nsCOMPtr<nsIContent> targetContent;
4436 mCurrentTarget->GetContentForEvent(aEvent,
4437 getter_AddRefs(targetContent));
4438 SetContentState(targetContent, ElementState::HOVER);
4439 }
4440 break;
4441
4442 case eMouseExitFromWidget:
4443 PointerEventHandler::UpdateActivePointerState(aEvent->AsMouseEvent());
4444 break;
4445
4446#ifdef XP_MACOSX
4447 case eMouseActivate:
4448 if (mCurrentTarget) {
4449 nsCOMPtr<nsIContent> targetContent;
4450 mCurrentTarget->GetContentForEvent(aEvent,
4451 getter_AddRefs(targetContent));
4452 if (!NodeAllowsClickThrough(targetContent)) {
4453 *aStatus = nsEventStatus_eConsumeNoDefault;
4454 }
4455 }
4456 break;
4457#endif
4458
4459 default:
4460 break;
4461 }
4462
4463 // Reset target frame to null to avoid mistargeting after reentrant event
4464 mCurrentTarget = nullptr;
4465 mCurrentTargetContent = nullptr;
4466
4467 return ret;
4468}
4469
4470BrowserParent* EventStateManager::GetCrossProcessTarget() {
4471 return IMEStateManager::GetActiveBrowserParent();
4472}
4473
4474bool EventStateManager::IsTargetCrossProcess(WidgetGUIEvent* aEvent) {
4475 // Check to see if there is a focused, editable content in chrome,
4476 // in that case, do not forward IME events to content
4477 Element* focusedElement = GetFocusedElement();
4478 if (focusedElement && focusedElement->IsEditable()) {
4479 return false;
4480 }
4481 return IMEStateManager::GetActiveBrowserParent() != nullptr;
4482}
4483
4484void EventStateManager::NotifyDestroyPresContext(nsPresContext* aPresContext) {
4485 RefPtr<nsPresContext> presContext = aPresContext;
4486 if (presContext) {
4487 IMEStateManager::OnDestroyPresContext(*presContext);
4488 }
4489
4490 // Bug 70855: Presentation is going away, possibly for a reframe.
4491 // Reset the hover state so that if we're recreating the presentation,
4492 // we won't have the old hover state still set in the new presentation,
4493 // as if the new presentation is resized, a new element may be hovered.
4494 ResetHoverState();
4495
4496 mMouseEnterLeaveHelper = nullptr;
4497 mPointersEnterLeaveHelper.Clear();
4498 PointerEventHandler::NotifyDestroyPresContext(presContext);
4499}
4500
4501void EventStateManager::ResetHoverState() {
4502 if (mHoverContent) {
4503 SetContentState(nullptr, ElementState::HOVER);
4504 }
4505}
4506
4507void EventStateManager::SetPresContext(nsPresContext* aPresContext) {
4508 mPresContext = aPresContext;
4509}
4510
4511void EventStateManager::ClearFrameRefs(nsIFrame* aFrame) {
4512 if (aFrame && aFrame == mCurrentTarget) {
4513 mCurrentTargetContent = aFrame->GetContent();
4514 }
4515}
4516
4517struct CursorImage {
4518 gfx::IntPoint mHotspot;
4519 nsCOMPtr<imgIContainer> mContainer;
4520 ImageResolution mResolution;
4521 bool mEarlierCursorLoading = false;
4522};
4523
4524// Given the event that we're processing, and the computed cursor and hotspot,
4525// determine whether the custom CSS cursor should be blocked (that is, not
4526// honored).
4527//
4528// We will not honor it all of the following are true:
4529//
4530// * the size of the custom cursor is bigger than layout.cursor.block.max-size.
4531// * the bounds of the cursor would end up outside of the viewport of the
4532// top-level content document.
4533//
4534// This is done in order to prevent hijacking the cursor, see bug 1445844 and
4535// co.
4536static bool ShouldBlockCustomCursor(nsPresContext* aPresContext,
4537 WidgetEvent* aEvent,
4538 const CursorImage& aCursor) {
4539 int32_t width = 0;
4540 int32_t height = 0;
4541 aCursor.mContainer->GetWidth(&width);
4542 aCursor.mContainer->GetHeight(&height);
4543 aCursor.mResolution.ApplyTo(width, height);
4544
4545 int32_t maxSize = StaticPrefs::layout_cursor_block_max_size();
4546
4547 if (width <= maxSize && height <= maxSize) {
4548 return false;
4549 }
4550
4551 auto input = DOMIntersectionObserver::ComputeInput(*aPresContext->Document(),
4552 nullptr, nullptr);
4553
4554 if (!input.mRootFrame) {
4555 return false;
4556 }
4557
4558 nsPoint point = nsLayoutUtils::GetEventCoordinatesRelativeTo(
4559 aEvent, RelativeTo{input.mRootFrame});
4560
4561 // The cursor size won't be affected by our full zoom in the parent process,
4562 // so undo that before checking the rect.
4563 float zoom = aPresContext->GetFullZoom();
4564
4565 // Also adjust for accessibility cursor scaling factor.
4566 zoom /= LookAndFeel::GetFloat(LookAndFeel::FloatID::CursorScale, 1.0f);
4567
4568 nsSize size(CSSPixel::ToAppUnits(width / zoom),
4569 CSSPixel::ToAppUnits(height / zoom));
4570 nsPoint hotspot(
4571 CSSPixel::ToAppUnits(ViewAs<CSSPixel>(aCursor.mHotspot.x / zoom)),
4572 CSSPixel::ToAppUnits(ViewAs<CSSPixel>(aCursor.mHotspot.y / zoom)));
4573
4574 const nsRect cursorRect(point - hotspot, size);
4575 auto output = DOMIntersectionObserver::Intersect(input, cursorRect);
4576 return !output.mIntersectionRect ||
4577 !(*output.mIntersectionRect == cursorRect);
4578}
4579
4580static gfx::IntPoint ComputeHotspot(imgIContainer* aContainer,
4581 const Maybe<gfx::Point>& aHotspot) {
4582 MOZ_ASSERT(aContainer)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContainer)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aContainer))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aContainer", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4582); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContainer"
")"); do { *((volatile int*)__null) = 4582; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4583
4584 // css3-ui says to use the CSS-specified hotspot if present,
4585 // otherwise use the intrinsic hotspot, otherwise use the top left
4586 // corner.
4587 if (aHotspot) {
4588 int32_t imgWidth, imgHeight;
4589 aContainer->GetWidth(&imgWidth);
4590 aContainer->GetHeight(&imgHeight);
4591 auto hotspot = gfx::IntPoint::Round(*aHotspot);
4592 return {std::max(std::min(hotspot.x.value, imgWidth - 1), 0),
4593 std::max(std::min(hotspot.y.value, imgHeight - 1), 0)};
4594 }
4595
4596 gfx::IntPoint hotspot;
4597 aContainer->GetHotspotX(&hotspot.x.value);
4598 aContainer->GetHotspotY(&hotspot.y.value);
4599 return hotspot;
4600}
4601
4602static CursorImage ComputeCustomCursor(nsPresContext* aPresContext,
4603 WidgetEvent* aEvent,
4604 const nsIFrame& aFrame,
4605 const nsIFrame::Cursor& aCursor) {
4606 if (aCursor.mAllowCustomCursor == nsIFrame::AllowCustomCursorImage::No) {
4607 return {};
4608 }
4609 const ComputedStyle& style =
4610 aCursor.mStyle ? *aCursor.mStyle : *aFrame.Style();
4611
4612 // If we are falling back because any cursor before us is loading, let the
4613 // consumer know.
4614 bool loading = false;
4615 for (const auto& image : style.StyleUI()->Cursor().images.AsSpan()) {
4616 MOZ_ASSERT(image.image.IsImageRequestType(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(image.image.IsImageRequestType())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(image.image.IsImageRequestType
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("image.image.IsImageRequestType()" " (" "Cursor image should only parse url() types"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4617); AnnotateMozCrashReason("MOZ_ASSERT" "(" "image.image.IsImageRequestType()"
") (" "Cursor image should only parse url() types" ")"); do {
*((volatile int*)__null) = 4617; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
4617 "Cursor image should only parse url() types")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(image.image.IsImageRequestType())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(image.image.IsImageRequestType
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("image.image.IsImageRequestType()" " (" "Cursor image should only parse url() types"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4617); AnnotateMozCrashReason("MOZ_ASSERT" "(" "image.image.IsImageRequestType()"
") (" "Cursor image should only parse url() types" ")"); do {
*((volatile int*)__null) = 4617; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
4618 uint32_t status;
4619 imgRequestProxy* req = image.image.GetImageRequest();
4620 if (!req || NS_FAILED(req->GetImageStatus(&status))((bool)(__builtin_expect(!!(NS_FAILED_impl(req->GetImageStatus
(&status))), 0)))
) {
4621 continue;
4622 }
4623 if (!(status & imgIRequest::STATUS_LOAD_COMPLETE)) {
4624 loading = true;
4625 continue;
4626 }
4627 if (status & imgIRequest::STATUS_ERROR) {
4628 continue;
4629 }
4630 nsCOMPtr<imgIContainer> container;
4631 req->GetImage(getter_AddRefs(container));
4632 if (!container) {
4633 continue;
4634 }
4635 StyleImageOrientation orientation =
4636 aFrame.StyleVisibility()->UsedImageOrientation(req);
4637 container = nsLayoutUtils::OrientImage(container, orientation);
4638 Maybe<gfx::Point> specifiedHotspot =
4639 image.has_hotspot ? Some(gfx::Point{image.hotspot_x, image.hotspot_y})
4640 : Nothing();
4641 gfx::IntPoint hotspot = ComputeHotspot(container, specifiedHotspot);
4642 CursorImage result{hotspot, std::move(container),
4643 image.image.GetResolution(style), loading};
4644 if (ShouldBlockCustomCursor(aPresContext, aEvent, result)) {
4645 continue;
4646 }
4647 // This is the one we want!
4648 return result;
4649 }
4650 return {{}, nullptr, {}, loading};
4651}
4652
4653void EventStateManager::UpdateCursor(nsPresContext* aPresContext,
4654 WidgetMouseEvent* aEvent,
4655 nsIFrame* aTargetFrame,
4656 nsEventStatus* aStatus) {
4657 if (aTargetFrame && IsRemoteTarget(aTargetFrame->GetContent())) {
4658 return;
4659 }
4660
4661 auto cursor = StyleCursorKind::Default;
4662 nsCOMPtr<imgIContainer> container;
4663 ImageResolution resolution;
4664 Maybe<gfx::IntPoint> hotspot;
4665
4666 if (mHidingCursorWhileTyping && aEvent->IsReal()) {
4667 // Any non-synthetic mouse event makes us show the cursor again.
4668 mHidingCursorWhileTyping = false;
4669 }
4670
4671 if (mHidingCursorWhileTyping) {
4672 cursor = StyleCursorKind::None;
4673 } else if (mLockCursor != kInvalidCursorKind) {
4674 // If cursor is locked just use the locked one
4675 cursor = mLockCursor;
4676 } else if (aTargetFrame) {
4677 // If not locked, look for correct cursor
4678 nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(
4679 aEvent, RelativeTo{aTargetFrame});
4680 const nsIFrame::Cursor framecursor = aTargetFrame->GetCursor(pt);
4681 const CursorImage customCursor =
4682 ComputeCustomCursor(aPresContext, aEvent, *aTargetFrame, framecursor);
4683
4684 // If the current cursor is from the same frame, and it is now
4685 // loading some new image for the cursor, we should wait for a
4686 // while rather than taking its fallback cursor directly.
4687 if (customCursor.mEarlierCursorLoading &&
4688 gLastCursorSourceFrame == aTargetFrame &&
4689 TimeStamp::NowLoRes() - gLastCursorUpdateTime <
4690 TimeDuration::FromMilliseconds(kCursorLoadingTimeout)) {
4691 return;
4692 }
4693 cursor = framecursor.mCursor;
4694 container = std::move(customCursor.mContainer);
4695 resolution = customCursor.mResolution;
4696 hotspot = Some(customCursor.mHotspot);
4697 }
4698
4699 if (aTargetFrame) {
4700 if (cursor == StyleCursorKind::Pointer && IsSelectingLink(aTargetFrame)) {
4701 cursor = aTargetFrame->GetWritingMode().IsVertical()
4702 ? StyleCursorKind::VerticalText
4703 : StyleCursorKind::Text;
4704 }
4705 SetCursor(cursor, container, resolution, hotspot,
4706 aTargetFrame->GetNearestWidget(), false);
4707 gLastCursorSourceFrame = aTargetFrame;
4708 gLastCursorUpdateTime = TimeStamp::NowLoRes();
4709 }
4710
4711 if (mLockCursor != kInvalidCursorKind || StyleCursorKind::Auto != cursor) {
4712 *aStatus = nsEventStatus_eConsumeDoDefault;
4713 }
4714}
4715
4716void EventStateManager::ClearCachedWidgetCursor(nsIFrame* aTargetFrame) {
4717 if (!aTargetFrame) {
4718 return;
4719 }
4720 nsIWidget* aWidget = aTargetFrame->GetNearestWidget();
4721 if (!aWidget) {
4722 return;
4723 }
4724 aWidget->ClearCachedCursor();
4725}
4726
4727void EventStateManager::StartHidingCursorWhileTyping(nsIWidget* aWidget) {
4728 if (mHidingCursorWhileTyping || sCursorSettingManager != this) {
4729 return;
4730 }
4731 mHidingCursorWhileTyping = true;
4732 SetCursor(StyleCursorKind::None, nullptr, {}, {}, aWidget, false);
4733}
4734
4735nsresult EventStateManager::SetCursor(StyleCursorKind aCursor,
4736 imgIContainer* aContainer,
4737 const ImageResolution& aResolution,
4738 const Maybe<gfx::IntPoint>& aHotspot,
4739 nsIWidget* aWidget, bool aLockCursor) {
4740 EnsureDocument(mPresContext);
4741 NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(mDocument)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mDocument" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4741); return NS_ERROR_FAILURE; } } while (false)
;
4742 sCursorSettingManager = this;
4743
4744 NS_ENSURE_TRUE(aWidget, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(aWidget)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aWidget" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4744); return NS_ERROR_FAILURE; } } while (false)
;
4745 if (aLockCursor) {
4746 if (StyleCursorKind::Auto != aCursor) {
4747 mLockCursor = aCursor;
4748 } else {
4749 // If cursor style is set to auto we unlock the cursor again.
4750 mLockCursor = kInvalidCursorKind;
4751 }
4752 }
4753 nsCursor c;
4754 switch (aCursor) {
4755 case StyleCursorKind::Auto:
4756 case StyleCursorKind::Default:
4757 c = eCursor_standard;
4758 break;
4759 case StyleCursorKind::Pointer:
4760 c = eCursor_hyperlink;
4761 break;
4762 case StyleCursorKind::Crosshair:
4763 c = eCursor_crosshair;
4764 break;
4765 case StyleCursorKind::Move:
4766 c = eCursor_move;
4767 break;
4768 case StyleCursorKind::Text:
4769 c = eCursor_select;
4770 break;
4771 case StyleCursorKind::Wait:
4772 c = eCursor_wait;
4773 break;
4774 case StyleCursorKind::Help:
4775 c = eCursor_help;
4776 break;
4777 case StyleCursorKind::NResize:
4778 c = eCursor_n_resize;
4779 break;
4780 case StyleCursorKind::SResize:
4781 c = eCursor_s_resize;
4782 break;
4783 case StyleCursorKind::WResize:
4784 c = eCursor_w_resize;
4785 break;
4786 case StyleCursorKind::EResize:
4787 c = eCursor_e_resize;
4788 break;
4789 case StyleCursorKind::NwResize:
4790 c = eCursor_nw_resize;
4791 break;
4792 case StyleCursorKind::SeResize:
4793 c = eCursor_se_resize;
4794 break;
4795 case StyleCursorKind::NeResize:
4796 c = eCursor_ne_resize;
4797 break;
4798 case StyleCursorKind::SwResize:
4799 c = eCursor_sw_resize;
4800 break;
4801 case StyleCursorKind::Copy: // CSS3
4802 c = eCursor_copy;
4803 break;
4804 case StyleCursorKind::Alias:
4805 c = eCursor_alias;
4806 break;
4807 case StyleCursorKind::ContextMenu:
4808 c = eCursor_context_menu;
4809 break;
4810 case StyleCursorKind::Cell:
4811 c = eCursor_cell;
4812 break;
4813 case StyleCursorKind::Grab:
4814 c = eCursor_grab;
4815 break;
4816 case StyleCursorKind::Grabbing:
4817 c = eCursor_grabbing;
4818 break;
4819 case StyleCursorKind::Progress:
4820 c = eCursor_spinning;
4821 break;
4822 case StyleCursorKind::ZoomIn:
4823 c = eCursor_zoom_in;
4824 break;
4825 case StyleCursorKind::ZoomOut:
4826 c = eCursor_zoom_out;
4827 break;
4828 case StyleCursorKind::NotAllowed:
4829 c = eCursor_not_allowed;
4830 break;
4831 case StyleCursorKind::ColResize:
4832 c = eCursor_col_resize;
4833 break;
4834 case StyleCursorKind::RowResize:
4835 c = eCursor_row_resize;
4836 break;
4837 case StyleCursorKind::NoDrop:
4838 c = eCursor_no_drop;
4839 break;
4840 case StyleCursorKind::VerticalText:
4841 c = eCursor_vertical_text;
4842 break;
4843 case StyleCursorKind::AllScroll:
4844 c = eCursor_all_scroll;
4845 break;
4846 case StyleCursorKind::NeswResize:
4847 c = eCursor_nesw_resize;
4848 break;
4849 case StyleCursorKind::NwseResize:
4850 c = eCursor_nwse_resize;
4851 break;
4852 case StyleCursorKind::NsResize:
4853 c = eCursor_ns_resize;
4854 break;
4855 case StyleCursorKind::EwResize:
4856 c = eCursor_ew_resize;
4857 break;
4858 case StyleCursorKind::None:
4859 c = eCursor_none;
4860 break;
4861 default:
4862 MOZ_ASSERT_UNREACHABLE("Unknown cursor kind")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Unknown cursor kind" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4862); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unknown cursor kind" ")"); do { *
((volatile int*)__null) = 4862; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
4863 c = eCursor_standard;
4864 break;
4865 }
4866
4867 uint32_t x = aHotspot ? aHotspot->x.value : 0;
4868 uint32_t y = aHotspot ? aHotspot->y.value : 0;
4869 aWidget->SetCursor(nsIWidget::Cursor{c, aContainer, x, y, aResolution});
4870 return NS_OK;
4871}
4872
4873bool EventStateManager::CursorSettingManagerHasLockedCursor() {
4874 return sCursorSettingManager &&
4875 sCursorSettingManager->mLockCursor != kInvalidCursorKind;
4876}
4877
4878class MOZ_STACK_CLASS ESMEventCB : public EventDispatchingCallback {
4879 public:
4880 explicit ESMEventCB(nsIContent* aTarget) : mTarget(aTarget) {}
4881
4882 MOZ_CAN_RUN_SCRIPT
4883 void HandleEvent(EventChainPostVisitor& aVisitor) override {
4884 if (aVisitor.mPresContext) {
4885 nsIFrame* frame = aVisitor.mPresContext->GetPrimaryFrameFor(mTarget);
4886 if (frame) {
4887 frame->HandleEvent(aVisitor.mPresContext, aVisitor.mEvent->AsGUIEvent(),
4888 &aVisitor.mEventStatus);
4889 }
4890 }
4891 }
4892
4893 nsCOMPtr<nsIContent> mTarget;
4894};
4895
4896static UniquePtr<WidgetMouseEvent> CreateMouseOrPointerWidgetEvent(
4897 WidgetMouseEvent* aMouseEvent, EventMessage aMessage,
4898 EventTarget* aRelatedTarget) {
4899 // This method does not support creating a mouse/pointer button change event
4900 // because of no data about the changing state.
4901 MOZ_ASSERT(aMessage != eMouseDown)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage != eMouseDown)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage != eMouseDown))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aMessage != eMouseDown"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4901); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != eMouseDown"
")"); do { *((volatile int*)__null) = 4901; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4902 MOZ_ASSERT(aMessage != eMouseUp)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage != eMouseUp)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage != eMouseUp))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("aMessage != eMouseUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4902); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != eMouseUp"
")"); do { *((volatile int*)__null) = 4902; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4903 MOZ_ASSERT(aMessage != ePointerDown)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage != ePointerDown)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage != ePointerDown))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aMessage != ePointerDown"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4903); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != ePointerDown"
")"); do { *((volatile int*)__null) = 4903; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4904 MOZ_ASSERT(aMessage != ePointerUp)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage != ePointerUp)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage != ePointerUp))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aMessage != ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4904); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != ePointerUp"
")"); do { *((volatile int*)__null) = 4904; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4905 // This method is currently designed to create the following events.
4906 MOZ_ASSERT(aMessage == eMouseOver || aMessage == eMouseEnter ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4911); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4911; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4907 aMessage == eMouseOut || aMessage == eMouseLeave ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4911); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4911; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4908 aMessage == ePointerOver || aMessage == ePointerEnter ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4911); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4911; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4909 aMessage == ePointerOut || aMessage == ePointerLeave ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4911); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4911; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4910 aMessage == eMouseEnterIntoWidget ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4911); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4911; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4911 aMessage == eMouseExitFromWidget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4911); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4911; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4912
4913 WidgetPointerEvent* sourcePointer = aMouseEvent->AsPointerEvent();
4914 UniquePtr<WidgetMouseEvent> newEvent;
4915 if (sourcePointer) {
4916 AUTO_PROFILER_LABEL("CreateMouseOrPointerWidgetEvent", OTHER)mozilla::AutoProfilerLabel raiiObject4916( "CreateMouseOrPointerWidgetEvent"
, nullptr, JS::ProfilingCategoryPair::OTHER)
;
4917
4918 WidgetPointerEvent* newPointerEvent = new WidgetPointerEvent(
4919 aMouseEvent->IsTrusted(), aMessage, aMouseEvent->mWidget);
4920 newPointerEvent->mIsPrimary = sourcePointer->mIsPrimary;
4921 newPointerEvent->mWidth = sourcePointer->mWidth;
4922 newPointerEvent->mHeight = sourcePointer->mHeight;
4923 newPointerEvent->mInputSource = sourcePointer->mInputSource;
4924
4925 newEvent = WrapUnique(newPointerEvent);
4926 } else {
4927 newEvent = MakeUnique<WidgetMouseEvent>(aMouseEvent->IsTrusted(), aMessage,
4928 aMouseEvent->mWidget,
4929 WidgetMouseEvent::eReal);
4930 }
4931
4932 // Inherit whether the event is synthesized by the test API or not.
4933 // Then, when the event is synthesized by a test API and handled in a remote
4934 // process, it won't be ignored. See PresShell::HandleEvent().
4935 newEvent->mFlags.mIsSynthesizedForTests =
4936 aMouseEvent->mFlags.mIsSynthesizedForTests;
4937
4938 newEvent->mRelatedTarget = aRelatedTarget;
4939 newEvent->mRefPoint = aMouseEvent->mRefPoint;
4940 newEvent->mModifiers = aMouseEvent->mModifiers;
4941 if (!aMouseEvent->mFlags.mDispatchedAtLeastOnce &&
4942 aMouseEvent->InputSourceSupportsHover()) {
4943 // If we synthesize a pointer event or a mouse event from another event
4944 // which changes a button state whose input soucre supports hover state and
4945 // the source event has not been dispatched yet, we should set to the button
4946 // state of the synthesizing event to previous one.
4947 // Note that we don't need to do this if the input source does not support
4948 // hover state because a WPT check the behavior (see below) and the other
4949 // browsers pass the test even though this is inconsistent behavior.
4950 newEvent->mButton =
4951 sourcePointer ? MouseButton::eNotPressed : MouseButton::ePrimary;
4952 if (aMouseEvent->IsPressingButton()) {
4953 // If the source event has not been dispatched into the DOM yet, we
4954 // need to remove the flag which is being pressed.
4955 newEvent->mButtons = static_cast<decltype(WidgetMouseEvent::mButtons)>(
4956 aMouseEvent->mButtons &
4957 ~MouseButtonsFlagToChange(
4958 static_cast<MouseButton>(aMouseEvent->mButton)));
4959 } else if (aMouseEvent->IsReleasingButton()) {
4960 // If the source event has not been dispatched into the DOM yet, we
4961 // need to add the flag which is being released.
4962 newEvent->mButtons = static_cast<decltype(WidgetMouseEvent::mButtons)>(
4963 aMouseEvent->mButtons |
4964 MouseButtonsFlagToChange(
4965 static_cast<MouseButton>(aMouseEvent->mButton)));
4966 } else {
4967 // The source event does not change the buttons state so that we can
4968 // set mButtons value as-is.
4969 newEvent->mButtons = aMouseEvent->mButtons;
4970 }
4971 // Adjust pressure if it does not matches with mButtons.
4972 // FIXME: We may use wrong pressure value if the source event has not been
4973 // dispatched into the DOM yet. However, fixing this requires to store the
4974 // last pressure value somewhere.
4975 if (newEvent->mButtons && aMouseEvent->mPressure == 0) {
4976 newEvent->mPressure = 0.5f;
4977 } else if (!newEvent->mButtons && aMouseEvent->mPressure != 0) {
4978 newEvent->mPressure = 0;
4979 } else {
4980 newEvent->mPressure = aMouseEvent->mPressure;
4981 }
4982 } else {
4983 // If the event has already been dispatched into the tree, web apps has
4984 // already handled the button state change, so the button state of the
4985 // source event has already synced.
4986 // If the input source does not have hover state, we don't need to modify
4987 // the state because the other browsers behave so and tested by
4988 // pointerevent_attributes_nohover_pointers.html even though this is
4989 // different expectation from
4990 // pointerevent_attributes_hoverable_pointers.html, but the other browsers
4991 // pass both of them.
4992 newEvent->mButton = aMouseEvent->mButton;
4993 newEvent->mButtons = aMouseEvent->mButtons;
4994 newEvent->mPressure = aMouseEvent->mPressure;
4995 }
4996
4997 newEvent->mInputSource = aMouseEvent->mInputSource;
4998 newEvent->pointerId = aMouseEvent->pointerId;
4999
5000 return newEvent;
5001}
5002
5003already_AddRefed<nsIWidget>
5004EventStateManager::DispatchMouseOrPointerBoundaryEvent(
5005 WidgetMouseEvent* aMouseEvent, EventMessage aMessage,
5006 nsIContent* aTargetContent, nsIContent* aRelatedContent) {
5007 MOZ_ASSERT(aMessage == eMouseEnter || aMessage == ePointerEnter ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseEnter || aMessage == ePointerEnter
|| aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage
== eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut
|| aMessage == ePointerOut)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseEnter || aMessage
== ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave
|| aMessage == eMouseOver || aMessage == ePointerOver || aMessage
== eMouseOut || aMessage == ePointerOut))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5010); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5010; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
65
Taking false branch
5008 aMessage == eMouseLeave || aMessage == ePointerLeave ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseEnter || aMessage == ePointerEnter
|| aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage
== eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut
|| aMessage == ePointerOut)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseEnter || aMessage
== ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave
|| aMessage == eMouseOver || aMessage == ePointerOver || aMessage
== eMouseOut || aMessage == ePointerOut))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5010); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5010; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5009 aMessage == eMouseOver || aMessage == ePointerOver ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseEnter || aMessage == ePointerEnter
|| aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage
== eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut
|| aMessage == ePointerOut)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseEnter || aMessage
== ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave
|| aMessage == eMouseOver || aMessage == ePointerOver || aMessage
== eMouseOut || aMessage == ePointerOut))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5010); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5010; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5010 aMessage == eMouseOut || aMessage == ePointerOut)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseEnter || aMessage == ePointerEnter
|| aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage
== eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut
|| aMessage == ePointerOut)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseEnter || aMessage
== ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave
|| aMessage == eMouseOver || aMessage == ePointerOver || aMessage
== eMouseOut || aMessage == ePointerOut))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5010); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5010; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5011
5012 // https://w3c.github.io/pointerlock/#dom-element-requestpointerlock
5013 // "[Once in the locked state...E]vents that require the concept
5014 // of a mouse cursor must not be dispatched (for example: mouseover,
5015 // mouseout...).
5016 // XXXedgar should we also block pointer events?
5017 if (PointerLockManager::IsLocked() &&
66
Loop condition is false. Exiting loop
67
Assuming the condition is true
68
Taking true branch
5018 (aMessage
67.1
'aMessage' is not equal to eMouseLeave
== eMouseLeave || aMessage
67.2
'aMessage' is not equal to eMouseEnter
== eMouseEnter ||
5019 aMessage
67.3
'aMessage' is not equal to eMouseOver
== eMouseOver || aMessage
67.4
'aMessage' is equal to eMouseOut
== eMouseOut)) {
5020 mCurrentTargetContent = nullptr;
5021 nsCOMPtr<Element> pointerLockedElement =
5022 PointerLockManager::GetLockedElement();
5023 if (!pointerLockedElement) {
69
Taking false branch
5024 NS_WARNING("Should have pointer locked element, but didn't.")NS_DebugBreak(NS_DEBUG_WARNING, "Should have pointer locked element, but didn't."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5024)
;
5025 return nullptr;
5026 }
5027 nsIFrame* const pointerLockedFrame =
70
'pointerLockedFrame' initialized here
5028 mPresContext->GetPrimaryFrameFor(pointerLockedElement);
5029 if (NS_WARN_IF(!pointerLockedFrame)NS_warn_if_impl(!pointerLockedFrame, "!pointerLockedFrame", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5029)
) {
71
Assuming 'pointerLockedFrame' is null
72
Assuming the condition is false
73
Taking false branch
5030 return nullptr;
5031 }
5032 return do_AddRef(pointerLockedFrame->GetNearestWidget());
74
Called C++ object pointer is null
5033 }
5034
5035 mCurrentTargetContent = nullptr;
5036
5037 if (!aTargetContent) {
5038 return nullptr;
5039 }
5040
5041 // Store the widget before dispatching the event because some event listeners
5042 // of the dispatching event may cause reframe the target or remove the target
5043 // from the tree.
5044 nsCOMPtr<nsIWidget> targetWidget;
5045 if (nsIFrame* const targetFrame =
5046 mPresContext->GetPrimaryFrameFor(aTargetContent)) {
5047 targetWidget = targetFrame->GetNearestWidget();
5048 }
5049
5050 nsCOMPtr<nsIContent> targetContent = aTargetContent;
5051 nsCOMPtr<nsIContent> relatedContent = aRelatedContent;
5052
5053 UniquePtr<WidgetMouseEvent> dispatchEvent =
5054 CreateMouseOrPointerWidgetEvent(aMouseEvent, aMessage, relatedContent);
5055
5056 AutoWeakFrame previousTarget = mCurrentTarget;
5057 mCurrentTargetContent = targetContent;
5058
5059 nsEventStatus status = nsEventStatus_eIgnore;
5060 ESMEventCB callback(targetContent);
5061 RefPtr<nsPresContext> presContext = mPresContext;
5062 EventDispatcher::Dispatch(targetContent, presContext, dispatchEvent.get(),
5063 nullptr, &status, &callback);
5064
5065 if (mPresContext) {
5066 // If we are entering/leaving remote content, dispatch a mouse enter/exit
5067 // event to the remote frame.
5068 if (IsTopLevelRemoteTarget(targetContent)) {
5069 if (aMessage == eMouseOut) {
5070 // For remote content, send a puppet widget mouse exit event.
5071 UniquePtr<WidgetMouseEvent> remoteEvent =
5072 CreateMouseOrPointerWidgetEvent(aMouseEvent, eMouseExitFromWidget,
5073 relatedContent);
5074 remoteEvent->mExitFrom = Some(WidgetMouseEvent::ePuppet);
5075
5076 // mCurrentTarget is set to the new target, so we must reset it to the
5077 // old target and then dispatch a cross-process event. (mCurrentTarget
5078 // will be set back below.) HandleCrossProcessEvent will query for the
5079 // proper target via GetEventTarget which will return mCurrentTarget.
5080 mCurrentTarget = mPresContext->GetPrimaryFrameFor(targetContent);
5081 HandleCrossProcessEvent(remoteEvent.get(), &status);
5082 } else if (aMessage == eMouseOver) {
5083 UniquePtr<WidgetMouseEvent> remoteEvent =
5084 CreateMouseOrPointerWidgetEvent(aMouseEvent, eMouseEnterIntoWidget,
5085 relatedContent);
5086 HandleCrossProcessEvent(remoteEvent.get(), &status);
5087 }
5088 }
5089 }
5090
5091 mCurrentTargetContent = nullptr;
5092 mCurrentTarget = previousTarget;
5093
5094 return targetWidget.forget();
5095}
5096
5097static nsIContent* FindCommonAncestor(nsIContent* aNode1, nsIContent* aNode2) {
5098 if (!aNode1 || !aNode2) {
5099 return nullptr;
5100 }
5101 return nsContentUtils::GetCommonFlattenedTreeAncestor(aNode1, aNode2);
5102}
5103
5104class EnterLeaveDispatcher {
5105 public:
5106 EnterLeaveDispatcher(EventStateManager* aESM, nsIContent* aTarget,
5107 nsIContent* aRelatedTarget,
5108 WidgetMouseEvent* aMouseEvent,
5109 EventMessage aEventMessage)
5110 : mESM(aESM), mMouseEvent(aMouseEvent), mEventMessage(aEventMessage) {
5111 nsPIDOMWindowInner* win =
5112 aTarget ? aTarget->OwnerDoc()->GetInnerWindow() : nullptr;
5113 if (aMouseEvent->AsPointerEvent()
5114 ? win && win->HasPointerEnterLeaveEventListeners()
5115 : win && win->HasMouseEnterLeaveEventListeners()) {
5116 mRelatedTarget =
5117 aRelatedTarget ? aRelatedTarget->FindFirstNonChromeOnlyAccessContent()
5118 : nullptr;
5119 nsINode* commonParent = FindCommonAncestor(aTarget, aRelatedTarget);
5120 nsIContent* current = aTarget;
5121 // Note, it is ok if commonParent is null!
5122 while (current && current != commonParent) {
5123 if (!current->ChromeOnlyAccess()) {
5124 mTargets.AppendObject(current);
5125 }
5126 // mouseenter/leave is fired only on elements.
5127 current = current->GetFlattenedTreeParent();
5128 }
5129 }
5130 }
5131
5132 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
5133 MOZ_CAN_RUN_SCRIPT_BOUNDARY void Dispatch() {
5134 if (mEventMessage == eMouseEnter || mEventMessage == ePointerEnter) {
5135 for (int32_t i = mTargets.Count() - 1; i >= 0; --i) {
5136 nsCOMPtr<nsIWidget> widget = mESM->DispatchMouseOrPointerBoundaryEvent(
5137 mMouseEvent, mEventMessage, MOZ_KnownLive(mTargets[i])(mTargets[i]),
5138 mRelatedTarget);
5139 }
5140 } else {
5141 for (int32_t i = 0; i < mTargets.Count(); ++i) {
5142 nsCOMPtr<nsIWidget> widget = mESM->DispatchMouseOrPointerBoundaryEvent(
5143 mMouseEvent, mEventMessage, MOZ_KnownLive(mTargets[i])(mTargets[i]),
5144 mRelatedTarget);
5145 }
5146 }
5147 }
5148
5149 // Nothing overwrites anything after constructor. Please remove MOZ_KnownLive
5150 // and MOZ_KNOWN_LIVE if anything marked as such becomes mutable.
5151 const RefPtr<EventStateManager> mESM;
5152 nsCOMArray<nsIContent> mTargets;
5153 MOZ_KNOWN_LIVE nsCOMPtr<nsIContent> mRelatedTarget;
5154 WidgetMouseEvent* mMouseEvent;
5155 EventMessage mEventMessage;
5156};
5157
5158void EventStateManager::NotifyMouseOut(WidgetMouseEvent* aMouseEvent,
5159 nsIContent* aMovingInto) {
5160 const bool isPointer = aMouseEvent->mClass == ePointerEventClass;
25
Assuming field 'mClass' is not equal to ePointerEventClass
44
Assuming field 'mClass' is not equal to ePointerEventClass
5161 LogModule* const logModule =
5162 isPointer
25.1
'isPointer' is false
44.1
'isPointer' is false
? sPointerBoundaryLog : sMouseBoundaryLog;
26
'?' condition is false
45
'?' condition is false
5163
5164 RefPtr<OverOutElementsWrapper> wrapper = GetWrapperByEventID(aMouseEvent);
5165
5166 // If there is no deepest "leave" event target, that means the last "over"
5167 // target has already been removed from the tree. Therefore, checking only
5168 // the "leave" event target is enough.
5169 if (!wrapper || !wrapper->GetDeepestLeaveEventTarget()) {
27
Assuming the condition is false
28
Taking false branch
46
Assuming the condition is false
47
Taking false branch
5170 return;
5171 }
5172 // Before firing "out" and/or "leave" events, check for recursion
5173 if (wrapper->IsDispatchingOutEventOnLastOverEventTarget()) {
29
Taking false branch
48
Taking false branch
5174 return;
5175 }
5176
5177 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOut: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
30
Assuming the condition is false
31
Taking true branch
32
'?' condition is false
33
Loop condition is false. Exiting loop
49
Assuming the condition is false
50
Taking true branch
51
'?' condition is false
52
Loop condition is false. Exiting loop
5178 ("NotifyMouseOut: the source event is %s (IsReal()=%s)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOut: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5179 ToChar(aMouseEvent->mMessage),do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOut: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5180 aMouseEvent->IsReal() ? "true" : "false"))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOut: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
;
5181
5182 // XXX If a content node is a container of remove content, it should be
5183 // replaced with them and its children should not be visible. Therefore,
5184 // if the deepest "enter" target is not the last "over" target, i.e., the
5185 // last "over" target has been removed from the DOM tree, it means that the
5186 // child/descendant was not replaced by remote content. So,
5187 // wrapper->GetOutEventTaget() may be enough here.
5188 if (RefPtr<nsFrameLoaderOwner> flo =
34
Taking true branch
53
Taking false branch
5189 do_QueryObject(wrapper->GetDeepestLeaveEventTarget())) {
5190 if (BrowsingContext* bc = flo->GetExtantBrowsingContext()) {
35
Assuming 'bc' is non-null
36
Taking true branch
5191 if (nsIDocShell* docshell = bc->GetDocShell()) {
37
Assuming 'docshell' is non-null
38
Taking true branch
5192 if (RefPtr<nsPresContext> presContext = docshell->GetPresContext()) {
39
Taking true branch
5193 EventStateManager* kidESM = presContext->EventStateManager();
5194 // Not moving into any element in this subdocument
5195 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying child EventStateManager (%p) of \"out\" "
"event...", kidESM); } } while (0)
40
Assuming the condition is false
41
Taking true branch
42
Loop condition is false. Exiting loop
5196 ("Notifying child EventStateManager (%p) of \"out\" "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying child EventStateManager (%p) of \"out\" "
"event...", kidESM); } } while (0)
5197 "event...",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying child EventStateManager (%p) of \"out\" "
"event...", kidESM); } } while (0)
5198 kidESM))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying child EventStateManager (%p) of \"out\" "
"event...", kidESM); } } while (0)
;
5199 kidESM->NotifyMouseOut(aMouseEvent, nullptr);
43
Calling 'EventStateManager::NotifyMouseOut'
5200 }
5201 }
5202 }
5203 }
5204 // That could have caused DOM events which could wreak havoc. Reverify
5205 // things and be careful.
5206 if (!wrapper->GetDeepestLeaveEventTarget()) {
54
Taking false branch
5207 return;
5208 }
5209
5210 wrapper->WillDispatchOutAndOrLeaveEvent();
5211
5212 // Don't touch hover state if aMovingInto is non-null. Caller will update
5213 // hover state itself, and we have optimizations for hover switching between
5214 // two nearby elements both deep in the DOM tree that would be defeated by
5215 // switching the hover state to null here.
5216 if (!aMovingInto
54.1
'aMovingInto' is null
&& !isPointer
54.2
'isPointer' is false
) {
55
Taking true branch
5217 // Unset :hover
5218 SetContentState(nullptr, ElementState::HOVER);
5219 }
5220
5221 EnterLeaveDispatcher leaveDispatcher(
5222 this, wrapper->GetDeepestLeaveEventTarget(), aMovingInto, aMouseEvent,
5223 isPointer
55.1
'isPointer' is false
? ePointerLeave : eMouseLeave);
56
'?' condition is false
5224
5225 // "out" events hould be fired only when the deepest "leave" event target
5226 // is the last "over" event target.
5227 if (nsCOMPtr<nsIContent> outEventTarget = wrapper->GetOutEventTarget()) {
57
Taking true branch
5228 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
58
Assuming the condition is false
59
Taking true branch
60
'?' condition is false
61
'?' condition is true
62
Loop condition is false. Exiting loop
5229 ("Dispatching %s event to %s (%p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
5230 isPointer ? "ePointerOut" : "eMouseOut",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
5231 outEventTarget ? ToString(*outEventTarget).c_str() : "nullptr",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
5232 outEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
;
5233 nsCOMPtr<nsIWidget> widget = DispatchMouseOrPointerBoundaryEvent(
64
Calling 'EventStateManager::DispatchMouseOrPointerBoundaryEvent'
5234 aMouseEvent, isPointer
62.1
'isPointer' is false
? ePointerOut : eMouseOut, outEventTarget,
63
'?' condition is false
5235 aMovingInto);
5236 }
5237
5238 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5239 ("Dispatching %s event to %s (%p) and its ancestors",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5240 isPointer ? "ePointerLeave" : "eMouseLeave",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5241 wrapper->GetDeepestLeaveEventTarget()do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5242 ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str()do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5243 : "nullptr",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5244 wrapper->GetDeepestLeaveEventTarget()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
;
5245 leaveDispatcher.Dispatch();
5246
5247 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"out\" and/or \"leave\" events"
); } } while (0)
5248 ("Dispatched \"out\" and/or \"leave\" events"))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"out\" and/or \"leave\" events"
); } } while (0)
;
5249 wrapper->DidDispatchOutAndOrLeaveEvent();
5250}
5251
5252void EventStateManager::RecomputeMouseEnterStateForRemoteFrame(
5253 Element& aElement) {
5254 if (!mMouseEnterLeaveHelper ||
5255 mMouseEnterLeaveHelper->GetDeepestLeaveEventTarget() != &aElement) {
5256 return;
5257 }
5258
5259 if (BrowserParent* remote = BrowserParent::GetFrom(&aElement)) {
5260 remote->MouseEnterIntoWidget();
5261 }
5262}
5263
5264void EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
5265 nsIContent* aContent) {
5266 NS_ASSERTION(aContent, "Mouse must be over something")do { if (!(aContent)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Mouse must be over something"
, "aContent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5266); MOZ_PretendNoReturn(); } } while (0)
;
5267
5268 const bool isPointer = aMouseEvent->mClass == ePointerEventClass;
5269 LogModule* const logModule =
5270 isPointer ? sPointerBoundaryLog : sMouseBoundaryLog;
5271
5272 RefPtr<OverOutElementsWrapper> wrapper = GetWrapperByEventID(aMouseEvent);
5273
5274 // If we have next "out" event target and it's the new "over" target, we don't
5275 // need to dispatch "out" nor "enter" event.
5276 if (!wrapper || aContent == wrapper->GetOutEventTarget()) {
5277 return;
5278 }
5279
5280 // Before firing "over" and "enter" events, check for recursion
5281 if (wrapper->IsDispatchingOverEventOn(aContent)) {
5282 return;
5283 }
5284
5285 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOver: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5286 ("NotifyMouseOver: the source event is %s (IsReal()=%s)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOver: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5287 ToChar(aMouseEvent->mMessage),do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOver: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5288 aMouseEvent->IsReal() ? "true" : "false"))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOver: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
;
5289
5290 // Check to see if we're a subdocument and if so update the parent
5291 // document's ESM state to indicate that the mouse is over the
5292 // content associated with our subdocument.
5293 EnsureDocument(mPresContext);
5294 if (Document* parentDoc = mDocument->GetInProcessParentDocument()) {
5295 if (nsCOMPtr<nsIContent> docContent = mDocument->GetEmbedderElement()) {
5296 if (PresShell* parentPresShell = parentDoc->GetPresShell()) {
5297 RefPtr<EventStateManager> parentESM =
5298 parentPresShell->GetPresContext()->EventStateManager();
5299 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying parent EventStateManager (%p) of \"over\" "
"event...", parentESM.get()); } } while (0)
5300 ("Notifying parent EventStateManager (%p) of \"over\" "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying parent EventStateManager (%p) of \"over\" "
"event...", parentESM.get()); } } while (0)
5301 "event...",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying parent EventStateManager (%p) of \"over\" "
"event...", parentESM.get()); } } while (0)
5302 parentESM.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying parent EventStateManager (%p) of \"over\" "
"event...", parentESM.get()); } } while (0)
;
5303 parentESM->NotifyMouseOver(aMouseEvent, docContent);
5304 }
5305 }
5306 }
5307 // Firing the DOM event in the parent document could cause all kinds
5308 // of havoc. Reverify and take care.
5309 if (aContent == wrapper->GetOutEventTarget()) {
5310 return;
5311 }
5312
5313 // Remember the deepest leave event target as the related content for the
5314 // DispatchMouseOrPointerBoundaryEvent() call below, since NotifyMouseOut()
5315 // resets it, bug 298477.
5316 nsCOMPtr<nsIContent> deepestLeaveEventTarget =
5317 wrapper->GetDeepestLeaveEventTarget();
5318
5319 EnterLeaveDispatcher enterDispatcher(this, aContent, deepestLeaveEventTarget,
5320 aMouseEvent,
5321 isPointer ? ePointerEnter : eMouseEnter);
5322
5323 if (!isPointer) {
5324 SetContentState(aContent, ElementState::HOVER);
5325 }
5326
5327 NotifyMouseOut(aMouseEvent, aContent);
5328
5329 wrapper->WillDispatchOverAndEnterEvent(aContent);
5330
5331 // Fire mouseover
5332 // XXX If aContent has already been removed from the DOM tree, what should we
5333 // do? At least, dispatching `mouseover` on it is odd.
5334 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOver" : "eMoustOver", aContent ? ToString(*aContent
).c_str() : "nullptr", aContent); } } while (0)
5335 ("Dispatching %s event to %s (%p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOver" : "eMoustOver", aContent ? ToString(*aContent
).c_str() : "nullptr", aContent); } } while (0)
5336 isPointer ? "ePointerOver" : "eMoustOver",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOver" : "eMoustOver", aContent ? ToString(*aContent
).c_str() : "nullptr", aContent); } } while (0)
5337 aContent ? ToString(*aContent).c_str() : "nullptr", aContent))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOver" : "eMoustOver", aContent ? ToString(*aContent
).c_str() : "nullptr", aContent); } } while (0)
;
5338 nsCOMPtr<nsIWidget> targetWidget = DispatchMouseOrPointerBoundaryEvent(
5339 aMouseEvent, isPointer ? ePointerOver : eMouseOver, aContent,
5340 deepestLeaveEventTarget);
5341
5342 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerEnter" : "eMouseEnter", aContent ? ToString
(*aContent).c_str() : "nullptr", aContent); } } while (0)
5343 ("Dispatching %s event to %s (%p) and its ancestors",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerEnter" : "eMouseEnter", aContent ? ToString
(*aContent).c_str() : "nullptr", aContent); } } while (0)
5344 isPointer ? "ePointerEnter" : "eMouseEnter",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerEnter" : "eMouseEnter", aContent ? ToString
(*aContent).c_str() : "nullptr", aContent); } } while (0)
5345 aContent ? ToString(*aContent).c_str() : "nullptr", aContent))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerEnter" : "eMouseEnter", aContent ? ToString
(*aContent).c_str() : "nullptr", aContent); } } while (0)
;
5346 enterDispatcher.Dispatch();
5347
5348 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"over\" and \"enter\" events (the original \"over\" "
"event target was in the document %p, and now in %p)", aContent
->GetComposedDoc(), mDocument.get()); } } while (0)
5349 ("Dispatched \"over\" and \"enter\" events (the original \"over\" "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"over\" and \"enter\" events (the original \"over\" "
"event target was in the document %p, and now in %p)", aContent
->GetComposedDoc(), mDocument.get()); } } while (0)
5350 "event target was in the document %p, and now in %p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"over\" and \"enter\" events (the original \"over\" "
"event target was in the document %p, and now in %p)", aContent
->GetComposedDoc(), mDocument.get()); } } while (0)
5351 aContent->GetComposedDoc(), mDocument.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"over\" and \"enter\" events (the original \"over\" "
"event target was in the document %p, and now in %p)", aContent
->GetComposedDoc(), mDocument.get()); } } while (0)
;
5352 wrapper->DidDispatchOverAndEnterEvent(
5353 aContent->GetComposedDoc() == mDocument ? aContent : nullptr,
5354 targetWidget);
5355}
5356
5357// Returns the center point of the window's client area. This is
5358// in widget coordinates, i.e. relative to the widget's top-left
5359// corner, not in screen coordinates, the same units that UIEvent::
5360// refpoint is in. It may not be the exact center of the window if
5361// the platform requires rounding the coordinate.
5362static LayoutDeviceIntPoint GetWindowClientRectCenter(nsIWidget* aWidget) {
5363 NS_ENSURE_TRUE(aWidget, LayoutDeviceIntPoint(0, 0))do { if ((__builtin_expect(!!(!(aWidget)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aWidget" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5363); return LayoutDeviceIntPoint(0, 0); } } while (false)
;
5364
5365 LayoutDeviceIntRect rect = aWidget->GetClientBounds();
5366 LayoutDeviceIntPoint point(rect.width / 2, rect.height / 2);
5367 int32_t round = aWidget->RoundsWidgetCoordinatesTo();
5368 point.x = point.x / round * round;
5369 point.y = point.y / round * round;
5370 return point;
5371}
5372
5373void EventStateManager::GeneratePointerEnterExit(EventMessage aMessage,
5374 WidgetMouseEvent* aEvent) {
5375 WidgetPointerEvent pointerEvent(*aEvent);
5376 pointerEvent.mMessage = aMessage;
5377 GenerateMouseEnterExit(&pointerEvent);
5378}
5379
5380/* static */
5381void EventStateManager::UpdateLastRefPointOfMouseEvent(
5382 WidgetMouseEvent* aMouseEvent) {
5383 if (aMouseEvent->mMessage != eMouseMove &&
5384 aMouseEvent->mMessage != ePointerMove) {
5385 return;
5386 }
5387
5388 // Mouse movement is reported on the MouseEvent.movement{X,Y} fields.
5389 // Movement is calculated in UIEvent::GetMovementPoint() as:
5390 // previous_mousemove_mRefPoint - current_mousemove_mRefPoint.
5391 if (PointerLockManager::IsLocked() && aMouseEvent->mWidget) {
5392 // The pointer is locked. If the pointer is not located at the center of
5393 // the window, dispatch a synthetic mousemove to return the pointer there.
5394 // Doing this between "real" pointer moves gives the impression that the
5395 // (locked) pointer can continue moving and won't stop at the screen
5396 // boundary. We cancel the synthetic event so that we don't end up
5397 // dispatching the centering move event to content.
5398 aMouseEvent->mLastRefPoint =
5399 GetWindowClientRectCenter(aMouseEvent->mWidget);
5400
5401 } else if (sLastRefPoint == kInvalidRefPoint) {
5402 // We don't have a valid previous mousemove mRefPoint. This is either
5403 // the first move we've encountered, or the mouse has just re-entered
5404 // the application window. We should report (0,0) movement for this
5405 // case, so make the current and previous mRefPoints the same.
5406 aMouseEvent->mLastRefPoint = aMouseEvent->mRefPoint;
5407 } else {
5408 aMouseEvent->mLastRefPoint = sLastRefPoint;
5409 }
5410}
5411
5412/* static */
5413void EventStateManager::ResetPointerToWindowCenterWhilePointerLocked(
5414 WidgetMouseEvent* aMouseEvent) {
5415 MOZ_ASSERT(PointerLockManager::IsLocked())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(PointerLockManager::IsLocked())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(PointerLockManager::IsLocked
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("PointerLockManager::IsLocked()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5415); AnnotateMozCrashReason("MOZ_ASSERT" "(" "PointerLockManager::IsLocked()"
")"); do { *((volatile int*)__null) = 5415; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5416 if ((aMouseEvent->mMessage != eMouseMove &&
5417 aMouseEvent->mMessage != ePointerMove) ||
5418 !aMouseEvent->mWidget) {
5419 return;
5420 }
5421
5422 // We generate pointermove from mousemove event, so only synthesize native
5423 // mouse move and update sSynthCenteringPoint by mousemove event.
5424 bool updateSynthCenteringPoint = aMouseEvent->mMessage == eMouseMove;
5425
5426 // The pointer is locked. If the pointer is not located at the center of
5427 // the window, dispatch a synthetic mousemove to return the pointer there.
5428 // Doing this between "real" pointer moves gives the impression that the
5429 // (locked) pointer can continue moving and won't stop at the screen
5430 // boundary. We cancel the synthetic event so that we don't end up
5431 // dispatching the centering move event to content.
5432 LayoutDeviceIntPoint center = GetWindowClientRectCenter(aMouseEvent->mWidget);
5433
5434 if (aMouseEvent->mRefPoint != center && updateSynthCenteringPoint) {
5435 // Mouse move doesn't finish at the center of the window. Dispatch a
5436 // synthetic native mouse event to move the pointer back to the center
5437 // of the window, to faciliate more movement. But first, record that
5438 // we've dispatched a synthetic mouse movement, so we can cancel it
5439 // in the other branch here.
5440 sSynthCenteringPoint = center;
5441 // XXX Once we fix XXX comments in SetPointerLock about this API, we could
5442 // restrict that this API works only in the automation mode or in the
5443 // pointer locked situation.
5444 aMouseEvent->mWidget->SynthesizeNativeMouseMove(
5445 center + aMouseEvent->mWidget->WidgetToScreenOffset(), nullptr);
5446 } else if (aMouseEvent->mRefPoint == sSynthCenteringPoint) {
5447 // This is the "synthetic native" event we dispatched to re-center the
5448 // pointer. Cancel it so we don't expose the centering move to content.
5449 aMouseEvent->StopPropagation();
5450 // Clear sSynthCenteringPoint so we don't cancel other events
5451 // targeted at the center.
5452 if (updateSynthCenteringPoint) {
5453 sSynthCenteringPoint = kInvalidRefPoint;
5454 }
5455 }
5456}
5457
5458/* static */
5459void EventStateManager::UpdateLastPointerPosition(
5460 WidgetMouseEvent* aMouseEvent) {
5461 if (aMouseEvent->mMessage != eMouseMove) {
5462 return;
5463 }
5464 sLastRefPoint = aMouseEvent->mRefPoint;
5465}
5466
5467void EventStateManager::GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent) {
5468 EnsureDocument(mPresContext);
5469 if (!mDocument) return;
16
Taking false branch
5470
5471 // Hold onto old target content through the event and reset after.
5472 nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
5473
5474 switch (aMouseEvent->mMessage) {
17
Control jumps to 'case ePointerUp:' at line 5492
5475 case eMouseMove:
5476 case ePointerMove:
5477 case ePointerDown:
5478 case ePointerGotCapture: {
5479 // Get the target content target (mousemove target == mouseover target)
5480 nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
5481 if (!targetElement) {
5482 // We're always over the document root, even if we're only
5483 // over dead space in a page (whose frame is not associated with
5484 // any content) or in print preview dead space
5485 targetElement = mDocument->GetRootElement();
5486 }
5487 if (targetElement) {
5488 NotifyMouseOver(aMouseEvent, targetElement);
5489 }
5490 break;
5491 }
5492 case ePointerUp: {
5493 if (!StaticPrefs::
18
Assuming the condition is false
19
Taking false branch
5494 dom_events_mouse_pointer_boundary_keep_enter_targets_after_over_target_removed()) {
5495 // In the legacy mode, we should do nothing if the event has not been
5496 // dispatched yet (i.e., called by PreHandleEvent).
5497 // On the other hand, if the event was dispatched (i.e., called by
5498 // PostEventHandler), we need to dispatch "pointerout" and
5499 // "pointerleave" events because the pointer will be removed
5500 // (invalidated) by the "pointerup" operation.
5501 if (!aMouseEvent->mFlags.mDispatchedAtLeastOnce) {
5502 break;
5503 }
5504 MOZ_ASSERT(!aMouseEvent->InputSourceSupportsHover())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aMouseEvent->InputSourceSupportsHover())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aMouseEvent->InputSourceSupportsHover()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aMouseEvent->InputSourceSupportsHover()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5504); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aMouseEvent->InputSourceSupportsHover()"
")"); do { *((volatile int*)__null) = 5504; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5505 // Get the target content target (pointermove target == pointerover
5506 // target)
5507 nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
5508 if (!targetElement) {
5509 // We're always over the document root, even if we're only
5510 // over dead space in a page (whose frame is not associated with
5511 // any content) or in print preview dead space
5512 targetElement = mDocument->GetRootElement();
5513 }
5514 if (targetElement) {
5515 // XXX It's odd to override the `pointerout` event target with the
5516 // content under the pointer or something because it may have never
5517 // received `pointerover` event. I think that this was required for
5518 // digitizer which supports hover state (bug 985511). However, this
5519 // is now not called at ePointerUp if the device supports hover.
5520 RefPtr<OverOutElementsWrapper> helper =
5521 GetWrapperByEventID(aMouseEvent);
5522 if (helper) {
5523 helper->OverrideOverEventTarget(targetElement);
5524 }
5525 NotifyMouseOut(aMouseEvent, nullptr);
5526 }
5527 break;
5528 }
5529
5530 if (aMouseEvent->mFlags.mDispatchedAtLeastOnce) {
20
Assuming field 'mDispatchedAtLeastOnce' is true
21
Taking true branch
5531 // If we've already dispatched the pointerup event caused by
5532 // non-hoverable input device like touch, we need to synthesize
5533 // pointerout and pointerleave events because the poiner is valid only
5534 // while it's "down".
5535 if (!aMouseEvent->InputSourceSupportsHover()) {
22
Assuming the condition is true
23
Taking true branch
5536 NotifyMouseOut(aMouseEvent, nullptr);
24
Calling 'EventStateManager::NotifyMouseOut'
5537 }
5538 break;
5539 }
5540
5541 // If we're going to dispatch the pointerup event and the element under
5542 // the pointer is changed from the previous pointer event dispatching, we
5543 // need to dispatch pointer boundary events. If the pointing device is
5544 // hoverable, we always need to do it. Otherwise, an element captures the
5545 // pointer by default. If so, we don't need the boundary events, but if
5546 // the capture has already been released, e.g., by the capturing element
5547 // is removed, we need to dispatch the pointer boundary event the same
5548 // way as with hoverable pointer.
5549 if (aMouseEvent->InputSourceSupportsHover() ||
5550 !PointerEventHandler::GetPointerCapturingElement(
5551 aMouseEvent->pointerId)) {
5552 nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
5553 if (!targetElement) {
5554 targetElement = mDocument->GetRootElement();
5555 }
5556 if (targetElement) {
5557 NotifyMouseOver(aMouseEvent, targetElement);
5558 }
5559 break;
5560 }
5561 break;
5562 }
5563 case ePointerLeave:
5564 case ePointerCancel:
5565 case eMouseExitFromWidget: {
5566 // This is actually the window mouse exit or pointer leave event. We're
5567 // not moving into any new element.
5568
5569 RefPtr<OverOutElementsWrapper> helper = GetWrapperByEventID(aMouseEvent);
5570 if (helper) {
5571 nsCOMPtr<nsIWidget> lastOverWidget = helper->GetLastOverWidget();
5572 if (lastOverWidget &&
5573 nsContentUtils::GetTopLevelWidget(aMouseEvent->mWidget) !=
5574 nsContentUtils::GetTopLevelWidget(lastOverWidget)) {
5575 // the Mouse/PointerOut event widget doesn't have same top widget with
5576 // the last over event target, it's a spurious event for the frame for
5577 // the target.
5578 break;
5579 }
5580 }
5581
5582 // Reset sLastRefPoint, so that we'll know not to report any
5583 // movement the next time we re-enter the window.
5584 sLastRefPoint = kInvalidRefPoint;
5585
5586 NotifyMouseOut(aMouseEvent, nullptr);
5587 break;
5588 }
5589 default:
5590 break;
5591 }
5592
5593 // reset mCurretTargetContent to what it was
5594 mCurrentTargetContent = targetBeforeEvent;
5595}
5596
5597OverOutElementsWrapper* EventStateManager::GetWrapperByEventID(
5598 WidgetMouseEvent* aEvent) {
5599 WidgetPointerEvent* pointer = aEvent->AsPointerEvent();
5600 if (!pointer) {
5601 MOZ_ASSERT(aEvent->AsMouseEvent() != nullptr)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->AsMouseEvent() != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->AsMouseEvent() !=
nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aEvent->AsMouseEvent() != nullptr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5601); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->AsMouseEvent() != nullptr"
")"); do { *((volatile int*)__null) = 5601; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5602 if (!mMouseEnterLeaveHelper) {
5603 mMouseEnterLeaveHelper = new OverOutElementsWrapper(
5604 OverOutElementsWrapper::BoundaryEventType::Mouse);
5605 }
5606 return mMouseEnterLeaveHelper;
5607 }
5608 return mPointersEnterLeaveHelper.GetOrInsertNew(
5609 pointer->pointerId, OverOutElementsWrapper::BoundaryEventType::Pointer);
5610}
5611
5612/* static */
5613void EventStateManager::SetPointerLock(nsIWidget* aWidget,
5614 nsPresContext* aPresContext) {
5615 // Reset mouse wheel transaction
5616 WheelTransaction::EndTransaction();
5617
5618 // Deal with DnD events
5619 nsCOMPtr<nsIDragService> dragService =
5620 do_GetService("@mozilla.org/widget/dragservice;1");
5621
5622 if (PointerLockManager::IsLocked()) {
5623 MOZ_ASSERT(aWidget, "Locking pointer requires a widget")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aWidget))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aWidget" " (" "Locking pointer requires a widget"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5623); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWidget" ") ("
"Locking pointer requires a widget" ")"); do { *((volatile int
*)__null) = 5623; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
5624 MOZ_ASSERT(aPresContext, "Locking pointer requires a presContext")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresContext))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPresContext" " ("
"Locking pointer requires a presContext" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5624); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresContext"
") (" "Locking pointer requires a presContext" ")"); do { *(
(volatile int*)__null) = 5624; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
5625
5626 // Release all pointer capture when a pointer lock is successfully applied
5627 // on an element.
5628 PointerEventHandler::ReleaseAllPointerCapture();
5629
5630 // Store the last known ref point so we can reposition the pointer after
5631 // unlock.
5632 sPreLockScreenPoint = LayoutDeviceIntPoint::Round(
5633 sLastScreenPoint * aPresContext->CSSToDevPixelScale());
5634
5635 // Fire a synthetic mouse move to ensure event state is updated. We first
5636 // set the mouse to the center of the window, so that the mouse event
5637 // doesn't report any movement.
5638 // XXX Cannot we do synthesize the native mousemove in the parent process
5639 // with calling LockNativePointer below? Then, we could make this API
5640 // work only in the automation mode.
5641 sLastRefPoint = GetWindowClientRectCenter(aWidget);
5642 aWidget->SynthesizeNativeMouseMove(
5643 sLastRefPoint + aWidget->WidgetToScreenOffset(), nullptr);
5644
5645 // Suppress DnD
5646 if (dragService) {
5647 dragService->Suppress();
5648 }
5649
5650 // Activate native pointer lock on platforms where it is required (Wayland)
5651 aWidget->LockNativePointer();
5652 } else {
5653 if (aWidget) {
5654 // Deactivate native pointer lock on platforms where it is required
5655 aWidget->UnlockNativePointer();
5656 }
5657
5658 // Reset SynthCenteringPoint to invalid so that next time we start
5659 // locking pointer, it has its initial value.
5660 sSynthCenteringPoint = kInvalidRefPoint;
5661 if (aWidget) {
5662 // Unlocking, so return pointer to the original position by firing a
5663 // synthetic mouse event. We first reset sLastRefPoint to its
5664 // pre-pointerlock position, so that the synthetic mouse event reports
5665 // no movement.
5666 sLastRefPoint = sPreLockScreenPoint - aWidget->WidgetToScreenOffset();
5667 // XXX Cannot we do synthesize the native mousemove in the parent process
5668 // with calling `UnlockNativePointer` above? Then, we could make this
5669 // API work only in the automation mode.
5670 aWidget->SynthesizeNativeMouseMove(sPreLockScreenPoint, nullptr);
5671 }
5672
5673 // Unsuppress DnD
5674 if (dragService) {
5675 dragService->Unsuppress();
5676 }
5677 }
5678}
5679
5680void EventStateManager::GenerateDragDropEnterExit(nsPresContext* aPresContext,
5681 WidgetDragEvent* aDragEvent) {
5682 // Hold onto old target content through the event and reset after.
5683 nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
5684
5685 switch (aDragEvent->mMessage) {
5686 case eDragOver: {
5687 // when dragging from one frame to another, events are fired in the
5688 // order: dragexit, dragenter, dragleave
5689 if (sLastDragOverFrame != mCurrentTarget) {
5690 // We'll need the content, too, to check if it changed separately from
5691 // the frames.
5692 nsCOMPtr<nsIContent> lastContent;
5693 nsCOMPtr<nsIContent> targetContent;
5694 mCurrentTarget->GetContentForEvent(aDragEvent,
5695 getter_AddRefs(targetContent));
5696 if (targetContent && targetContent->IsText()) {
5697 targetContent = targetContent->GetFlattenedTreeParent();
5698 }
5699
5700 if (sLastDragOverFrame) {
5701 // The frame has changed but the content may not have. Check before
5702 // dispatching to content
5703 sLastDragOverFrame->GetContentForEvent(aDragEvent,
5704 getter_AddRefs(lastContent));
5705 if (lastContent && lastContent->IsText()) {
5706 lastContent = lastContent->GetFlattenedTreeParent();
5707 }
5708
5709 RefPtr<nsPresContext> presContext = sLastDragOverFrame->PresContext();
5710 FireDragEnterOrExit(presContext, aDragEvent, eDragExit, targetContent,
5711 lastContent, sLastDragOverFrame);
5712 nsIContent* target = sLastDragOverFrame
5713 ? sLastDragOverFrame.GetFrame()->GetContent()
5714 : nullptr;
5715 // XXXedgar, look like we need to consider fission OOP iframe, too.
5716 if (IsTopLevelRemoteTarget(target)) {
5717 // Dragging something and moving from web content to chrome only
5718 // fires dragexit and dragleave to xul:browser. We have to forward
5719 // dragexit to sLastDragOverFrame when its content is a remote
5720 // target. We don't forward dragleave since it's generated from
5721 // dragexit.
5722 WidgetDragEvent remoteEvent(aDragEvent->IsTrusted(), eDragExit,
5723 aDragEvent->mWidget);
5724 remoteEvent.AssignDragEventData(*aDragEvent, true);
5725 remoteEvent.mFlags.mIsSynthesizedForTests =
5726 aDragEvent->mFlags.mIsSynthesizedForTests;
5727 nsEventStatus remoteStatus = nsEventStatus_eIgnore;
5728 HandleCrossProcessEvent(&remoteEvent, &remoteStatus);
5729 }
5730 }
5731
5732 AutoWeakFrame currentTraget = mCurrentTarget;
5733 FireDragEnterOrExit(aPresContext, aDragEvent, eDragEnter, lastContent,
5734 targetContent, currentTraget);
5735
5736 if (sLastDragOverFrame) {
5737 RefPtr<nsPresContext> presContext = sLastDragOverFrame->PresContext();
5738 FireDragEnterOrExit(presContext, aDragEvent, eDragLeave,
5739 targetContent, lastContent, sLastDragOverFrame);
5740 }
5741
5742 sLastDragOverFrame = mCurrentTarget;
5743 }
5744 } break;
5745
5746 case eDragExit: {
5747 // This is actually the window mouse exit event.
5748 if (sLastDragOverFrame) {
5749 nsCOMPtr<nsIContent> lastContent;
5750 sLastDragOverFrame->GetContentForEvent(aDragEvent,
5751 getter_AddRefs(lastContent));
5752
5753 RefPtr<nsPresContext> lastDragOverFramePresContext =
5754 sLastDragOverFrame->PresContext();
5755 FireDragEnterOrExit(lastDragOverFramePresContext, aDragEvent, eDragExit,
5756 nullptr, lastContent, sLastDragOverFrame);
5757 FireDragEnterOrExit(lastDragOverFramePresContext, aDragEvent,
5758 eDragLeave, nullptr, lastContent,
5759 sLastDragOverFrame);
5760
5761 sLastDragOverFrame = nullptr;
5762 }
5763 } break;
5764
5765 default:
5766 break;
5767 }
5768
5769 // reset mCurretTargetContent to what it was
5770 mCurrentTargetContent = targetBeforeEvent;
5771
5772 // Now flush all pending notifications, for better responsiveness.
5773 FlushLayout(aPresContext);
5774}
5775
5776void EventStateManager::FireDragEnterOrExit(nsPresContext* aPresContext,
5777 WidgetDragEvent* aDragEvent,
5778 EventMessage aMessage,
5779 nsIContent* aRelatedTarget,
5780 nsIContent* aTargetContent,
5781 AutoWeakFrame& aTargetFrame) {
5782 MOZ_ASSERT(aMessage == eDragLeave || aMessage == eDragExit ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eDragLeave || aMessage == eDragExit || aMessage
== eDragEnter)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aMessage == eDragLeave || aMessage
== eDragExit || aMessage == eDragEnter))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eDragLeave || aMessage == eDragExit || aMessage == eDragEnter"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5783); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eDragLeave || aMessage == eDragExit || aMessage == eDragEnter"
")"); do { *((volatile int*)__null) = 5783; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5783 aMessage == eDragEnter)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eDragLeave || aMessage == eDragExit || aMessage
== eDragEnter)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aMessage == eDragLeave || aMessage
== eDragExit || aMessage == eDragEnter))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eDragLeave || aMessage == eDragExit || aMessage == eDragEnter"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5783); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eDragLeave || aMessage == eDragExit || aMessage == eDragEnter"
")"); do { *((volatile int*)__null) = 5783; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5784 nsEventStatus status = nsEventStatus_eIgnore;
5785 WidgetDragEvent event(aDragEvent->IsTrusted(), aMessage, aDragEvent->mWidget);
5786 event.AssignDragEventData(*aDragEvent, false);
5787 event.mFlags.mIsSynthesizedForTests =
5788 aDragEvent->mFlags.mIsSynthesizedForTests;
5789 event.mRelatedTarget = aRelatedTarget;
5790 if (aMessage == eDragExit && !StaticPrefs::dom_event_dragexit_enabled()) {
5791 event.mFlags.mOnlyChromeDispatch = true;
5792 }
5793
5794 mCurrentTargetContent = aTargetContent;
5795
5796 if (aTargetContent != aRelatedTarget) {
5797 // XXX This event should still go somewhere!!
5798 if (aTargetContent) {
5799 EventDispatcher::Dispatch(aTargetContent, aPresContext, &event, nullptr,
5800 &status);
5801 }
5802
5803 // adjust the drag hover if the dragenter event was cancelled or this is a
5804 // drag exit
5805 if (status == nsEventStatus_eConsumeNoDefault || aMessage == eDragExit) {
5806 SetContentState((aMessage == eDragEnter) ? aTargetContent : nullptr,
5807 ElementState::DRAGOVER);
5808 }
5809
5810 // collect any changes to moz cursor settings stored in the event's
5811 // data transfer.
5812 UpdateDragDataTransfer(&event);
5813 }
5814
5815 // Finally dispatch the event to the frame
5816 if (aTargetFrame) {
5817 aTargetFrame->HandleEvent(aPresContext, &event, &status);
5818 }
5819}
5820
5821void EventStateManager::UpdateDragDataTransfer(WidgetDragEvent* dragEvent) {
5822 NS_ASSERTION(dragEvent, "drag event is null in UpdateDragDataTransfer!")do { if (!(dragEvent)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "drag event is null in UpdateDragDataTransfer!"
, "dragEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5822); MOZ_PretendNoReturn(); } } while (0)
;
5823 if (!dragEvent->mDataTransfer) {
5824 return;
5825 }
5826
5827 nsCOMPtr<nsIDragSession> dragSession =
5828 nsContentUtils::GetDragSession(mPresContext);
5829
5830 if (dragSession) {
5831 // the initial dataTransfer is the one from the dragstart event that
5832 // was set on the dragSession when the drag began.
5833 RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer();
5834 if (initialDataTransfer) {
5835 // retrieve the current moz cursor setting and save it.
5836 nsAutoString mozCursor;
5837 dragEvent->mDataTransfer->GetMozCursor(mozCursor);
5838 initialDataTransfer->SetMozCursor(mozCursor);
5839 }
5840 }
5841}
5842
5843nsresult EventStateManager::SetClickCount(WidgetMouseEvent* aEvent,
5844 nsEventStatus* aStatus,
5845 nsIContent* aOverrideClickTarget) {
5846 nsCOMPtr<nsIContent> mouseContent = aOverrideClickTarget;
5847 if (!mouseContent && mCurrentTarget) {
5848 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(mouseContent));
5849 }
5850 if (mouseContent && mouseContent->IsText()) {
5851 nsINode* parent = mouseContent->GetFlattenedTreeParentNode();
5852 if (parent && parent->IsContent()) {
5853 mouseContent = parent->AsContent();
5854 }
5855 }
5856
5857 LastMouseDownInfo& mouseDownInfo = GetLastMouseDownInfo(aEvent->mButton);
5858 if (aEvent->mMessage == eMouseDown) {
5859 mouseDownInfo.mLastMouseDownContent =
5860 !aEvent->mClickEventPrevented ? mouseContent : nullptr;
5861
5862 if (mouseDownInfo.mLastMouseDownContent) {
5863 if (HTMLInputElement* input = HTMLInputElement::FromNodeOrNull(
5864 mouseDownInfo.mLastMouseDownContent)) {
5865 mouseDownInfo.mLastMouseDownInputControlType =
5866 Some(input->ControlType());
5867 } else if (mouseDownInfo.mLastMouseDownContent
5868 ->IsInNativeAnonymousSubtree()) {
5869 if (HTMLInputElement* input = HTMLInputElement::FromNodeOrNull(
5870 mouseDownInfo.mLastMouseDownContent
5871 ->GetFlattenedTreeParent())) {
5872 mouseDownInfo.mLastMouseDownInputControlType =
5873 Some(input->ControlType());
5874 }
5875 }
5876 }
5877 } else {
5878 aEvent->mClickTarget =
5879 !aEvent->mClickEventPrevented
5880 ? GetCommonAncestorForMouseUp(
5881 mouseContent, mouseDownInfo.mLastMouseDownContent,
5882 mouseDownInfo.mLastMouseDownInputControlType)
5883 : nullptr;
5884 if (aEvent->mClickTarget) {
5885 aEvent->mClickCount = mouseDownInfo.mClickCount;
5886 mouseDownInfo.mClickCount = 0;
5887 } else {
5888 aEvent->mClickCount = 0;
5889 }
5890 mouseDownInfo.mLastMouseDownContent = nullptr;
5891 mouseDownInfo.mLastMouseDownInputControlType = Nothing();
5892 }
5893
5894 return NS_OK;
5895}
5896
5897// static
5898bool EventStateManager::EventCausesClickEvents(
5899 const WidgetMouseEvent& aMouseEvent) {
5900 if (NS_WARN_IF(aMouseEvent.mMessage != eMouseUp)NS_warn_if_impl(aMouseEvent.mMessage != eMouseUp, "aMouseEvent.mMessage != eMouseUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5900)
) {
5901 return false;
5902 }
5903 // If the mouseup event is synthesized event, we don't need to dispatch
5904 // click events.
5905 if (!aMouseEvent.IsReal()) {
5906 return false;
5907 }
5908 // If mouse is still over same element, clickcount will be > 1.
5909 // If it has moved it will be zero, so no click.
5910 if (!aMouseEvent.mClickCount || !aMouseEvent.mClickTarget) {
5911 return false;
5912 }
5913 // If click event was explicitly prevented, we shouldn't dispatch it.
5914 if (aMouseEvent.mClickEventPrevented) {
5915 return false;
5916 }
5917 // Check that the window isn't disabled before firing a click
5918 // (see bug 366544).
5919 return !(aMouseEvent.mWidget && !aMouseEvent.mWidget->IsEnabled());
5920}
5921
5922nsresult EventStateManager::InitAndDispatchClickEvent(
5923 WidgetMouseEvent* aMouseUpEvent, nsEventStatus* aStatus,
5924 EventMessage aMessage, PresShell* aPresShell, nsIContent* aMouseUpContent,
5925 AutoWeakFrame aCurrentTarget, bool aNoContentDispatch,
5926 nsIContent* aOverrideClickTarget) {
5927 MOZ_ASSERT(aMouseUpEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseUpEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseUpEvent))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aMouseUpEvent",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5927); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpEvent"
")"); do { *((volatile int*)__null) = 5927; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5928 MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(EventCausesClickEvents(*aMouseUpEvent))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(EventCausesClickEvents(*aMouseUpEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("EventCausesClickEvents(*aMouseUpEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5928); AnnotateMozCrashReason("MOZ_ASSERT" "(" "EventCausesClickEvents(*aMouseUpEvent)"
")"); do { *((volatile int*)__null) = 5928; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5929 MOZ_ASSERT(aMouseUpContent || aCurrentTarget || aOverrideClickTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseUpContent || aCurrentTarget || aOverrideClickTarget
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aMouseUpContent || aCurrentTarget || aOverrideClickTarget
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aMouseUpContent || aCurrentTarget || aOverrideClickTarget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5929); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpContent || aCurrentTarget || aOverrideClickTarget"
")"); do { *((volatile int*)__null) = 5929; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5930
5931 Maybe<WidgetPointerEvent> pointerEvent;
5932 Maybe<WidgetMouseEvent> mouseEvent;
5933 if (IsPointerEventMessage(aMessage)) {
5934 pointerEvent.emplace(aMouseUpEvent->IsTrusted(), aMessage,
5935 aMouseUpEvent->mWidget);
5936 } else {
5937 mouseEvent.emplace(aMouseUpEvent->IsTrusted(), aMessage,
5938 aMouseUpEvent->mWidget, WidgetMouseEvent::eReal);
5939 }
5940
5941 WidgetMouseEvent& mouseOrPointerEvent =
5942 pointerEvent.isSome() ? pointerEvent.ref() : mouseEvent.ref();
5943
5944 mouseOrPointerEvent.mRefPoint = aMouseUpEvent->mRefPoint;
5945 mouseOrPointerEvent.mClickCount = aMouseUpEvent->mClickCount;
5946 mouseOrPointerEvent.mModifiers = aMouseUpEvent->mModifiers;
5947 mouseOrPointerEvent.mButtons = aMouseUpEvent->mButtons;
5948 mouseOrPointerEvent.mTimeStamp = aMouseUpEvent->mTimeStamp;
5949 mouseOrPointerEvent.mFlags.mOnlyChromeDispatch = aNoContentDispatch;
5950 mouseOrPointerEvent.mFlags.mNoContentDispatch = aNoContentDispatch;
5951 mouseOrPointerEvent.mButton = aMouseUpEvent->mButton;
5952 mouseOrPointerEvent.pointerId = aMouseUpEvent->pointerId;
5953 mouseOrPointerEvent.mInputSource = aMouseUpEvent->mInputSource;
5954 nsIContent* target = aMouseUpContent;
5955 nsIFrame* targetFrame = aCurrentTarget;
5956 if (aOverrideClickTarget) {
5957 target = aOverrideClickTarget;
5958 targetFrame = aOverrideClickTarget->GetPrimaryFrame();
5959 }
5960
5961 if (!target->IsInComposedDoc()) {
5962 return NS_OK;
5963 }
5964
5965 // Use local event status for each click event dispatching since it'll be
5966 // cleared by EventStateManager::PreHandleEvent(). Therefore, dispatching
5967 // an event means that previous event status will be ignored.
5968 nsEventStatus status = nsEventStatus_eIgnore;
5969 nsresult rv = aPresShell->HandleEventWithTarget(
5970 &mouseOrPointerEvent, targetFrame, MOZ_KnownLive(target)(target), &status);
5971
5972 // Copy mMultipleActionsPrevented flag from a click event to the mouseup
5973 // event only when it's set to true. It may be set to true if an editor has
5974 // already handled it. This is important to avoid two or more default
5975 // actions handled here.
5976 aMouseUpEvent->mFlags.mMultipleActionsPrevented |=
5977 mouseOrPointerEvent.mFlags.mMultipleActionsPrevented;
5978 // If current status is nsEventStatus_eConsumeNoDefault, we don't need to
5979 // overwrite it.
5980 if (*aStatus == nsEventStatus_eConsumeNoDefault) {
5981 return rv;
5982 }
5983 // If new status is nsEventStatus_eConsumeNoDefault or
5984 // nsEventStatus_eConsumeDoDefault, use it.
5985 if (status == nsEventStatus_eConsumeNoDefault ||
5986 status == nsEventStatus_eConsumeDoDefault) {
5987 *aStatus = status;
5988 return rv;
5989 }
5990 // Otherwise, keep the original status.
5991 return rv;
5992}
5993
5994nsresult EventStateManager::PostHandleMouseUp(
5995 WidgetMouseEvent* aMouseUpEvent, nsEventStatus* aStatus,
5996 nsIContent* aOverrideClickTarget) {
5997 MOZ_ASSERT(aMouseUpEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseUpEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseUpEvent))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aMouseUpEvent",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5997); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpEvent"
")"); do { *((volatile int*)__null) = 5997; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5998 MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(EventCausesClickEvents(*aMouseUpEvent))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(EventCausesClickEvents(*aMouseUpEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("EventCausesClickEvents(*aMouseUpEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5998); AnnotateMozCrashReason("MOZ_ASSERT" "(" "EventCausesClickEvents(*aMouseUpEvent)"
")"); do { *((volatile int*)__null) = 5998; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5999 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5999); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 5999; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6000
6001 RefPtr<PresShell> presShell = mPresContext->GetPresShell();
6002 if (!presShell) {
6003 return NS_OK;
6004 }
6005
6006 nsCOMPtr<nsIContent> clickTarget =
6007 nsIContent::FromEventTargetOrNull(aMouseUpEvent->mClickTarget);
6008 NS_ENSURE_STATE(clickTarget)do { if ((__builtin_expect(!!(!(clickTarget)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "clickTarget" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6008); return NS_ERROR_UNEXPECTED; } } while (false)
;
6009
6010 // Fire click events if the event target is still available.
6011 // Note that do not include the eMouseUp event's status since we ignore it
6012 // for compatibility with the other browsers.
6013 nsEventStatus status = nsEventStatus_eIgnore;
6014 nsresult rv = DispatchClickEvents(presShell, aMouseUpEvent, &status,
6015 clickTarget, aOverrideClickTarget);
6016 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6016)
) {
6017 return rv;
6018 }
6019
6020 // Do not do anything if preceding click events are consumed.
6021 // Note that Chromium dispatches "paste" event and actually pates clipboard
6022 // text into focused editor even if the preceding click events are consumed.
6023 // However, this is different from our traditional behavior and does not
6024 // conform to DOM events. If we need to keep compatibility with Chromium,
6025 // we should change it later.
6026 if (status == nsEventStatus_eConsumeNoDefault) {
6027 *aStatus = nsEventStatus_eConsumeNoDefault;
6028 return NS_OK;
6029 }
6030
6031 // Handle middle click paste if it's enabled and the mouse button is middle.
6032 if (aMouseUpEvent->mButton != MouseButton::eMiddle ||
6033 !WidgetMouseEvent::IsMiddleClickPasteEnabled()) {
6034 return NS_OK;
6035 }
6036 DebugOnly<nsresult> rvIgnored =
6037 HandleMiddleClickPaste(presShell, aMouseUpEvent, &status, nullptr);
6038 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to paste for a middle click"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6039); } } while (false)
6039 "Failed to paste for a middle click")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to paste for a middle click"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6039); } } while (false)
;
6040
6041 // If new status is nsEventStatus_eConsumeNoDefault or
6042 // nsEventStatus_eConsumeDoDefault, use it.
6043 if (*aStatus != nsEventStatus_eConsumeNoDefault &&
6044 (status == nsEventStatus_eConsumeNoDefault ||
6045 status == nsEventStatus_eConsumeDoDefault)) {
6046 *aStatus = status;
6047 }
6048
6049 // Don't return error even if middle mouse paste fails since we haven't
6050 // handled it here.
6051 return NS_OK;
6052}
6053
6054nsresult EventStateManager::DispatchClickEvents(
6055 PresShell* aPresShell, WidgetMouseEvent* aMouseUpEvent,
6056 nsEventStatus* aStatus, nsIContent* aClickTarget,
6057 nsIContent* aOverrideClickTarget) {
6058 MOZ_ASSERT(aPresShell)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresShell)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresShell))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aPresShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6058); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresShell"
")"); do { *((volatile int*)__null) = 6058; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6059 MOZ_ASSERT(aMouseUpEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseUpEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseUpEvent))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aMouseUpEvent",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6059); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpEvent"
")"); do { *((volatile int*)__null) = 6059; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6060 MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(EventCausesClickEvents(*aMouseUpEvent))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(EventCausesClickEvents(*aMouseUpEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("EventCausesClickEvents(*aMouseUpEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6060); AnnotateMozCrashReason("MOZ_ASSERT" "(" "EventCausesClickEvents(*aMouseUpEvent)"
")"); do { *((volatile int*)__null) = 6060; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6061 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6061); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 6061; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6062 MOZ_ASSERT(aClickTarget || aOverrideClickTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aClickTarget || aOverrideClickTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aClickTarget || aOverrideClickTarget
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aClickTarget || aOverrideClickTarget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6062); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aClickTarget || aOverrideClickTarget"
")"); do { *((volatile int*)__null) = 6062; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6063
6064 bool notDispatchToContents =
6065 (aMouseUpEvent->mButton == MouseButton::eMiddle ||
6066 aMouseUpEvent->mButton == MouseButton::eSecondary);
6067
6068 bool fireAuxClick = notDispatchToContents;
6069
6070 AutoWeakFrame currentTarget = aClickTarget->GetPrimaryFrame();
6071 nsresult rv = InitAndDispatchClickEvent(
6072 aMouseUpEvent, aStatus, ePointerClick, aPresShell, aClickTarget,
6073 currentTarget, notDispatchToContents, aOverrideClickTarget);
6074 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6074)
) {
6075 return rv;
6076 }
6077
6078 // Fire auxclick event if necessary.
6079 if (fireAuxClick && *aStatus != nsEventStatus_eConsumeNoDefault &&
6080 aClickTarget && aClickTarget->IsInComposedDoc()) {
6081 rv = InitAndDispatchClickEvent(aMouseUpEvent, aStatus, ePointerAuxClick,
6082 aPresShell, aClickTarget, currentTarget,
6083 false, aOverrideClickTarget);
6084 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to dispatch ePointerAuxClick"
, "NS_SUCCEEDED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6085); } } while (false)
6085 "Failed to dispatch ePointerAuxClick")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to dispatch ePointerAuxClick"
, "NS_SUCCEEDED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6085); } } while (false)
;
6086 }
6087
6088 // Fire double click event if click count is 2.
6089 if (aMouseUpEvent->mClickCount == 2 && !fireAuxClick && aClickTarget &&
6090 aClickTarget->IsInComposedDoc()) {
6091 rv = InitAndDispatchClickEvent(aMouseUpEvent, aStatus, eMouseDoubleClick,
6092 aPresShell, aClickTarget, currentTarget,
6093 notDispatchToContents, aOverrideClickTarget);
6094 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6094)
) {
6095 return rv;
6096 }
6097 }
6098
6099 return rv;
6100}
6101
6102nsresult EventStateManager::HandleMiddleClickPaste(
6103 PresShell* aPresShell, WidgetMouseEvent* aMouseEvent,
6104 nsEventStatus* aStatus, EditorBase* aEditorBase) {
6105 MOZ_ASSERT(aPresShell)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresShell)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresShell))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aPresShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6105); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresShell"
")"); do { *((volatile int*)__null) = 6105; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6106 MOZ_ASSERT(aMouseEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseEvent))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aMouseEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6106); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseEvent"
")"); do { *((volatile int*)__null) = 6106; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6107 MOZ_ASSERT((aMouseEvent->mMessage == ePointerAuxClick &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aMouseEvent->mMessage == ePointerAuxClick &&
aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents
(*aMouseEvent))>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!((aMouseEvent->mMessage == ePointerAuxClick
&& aMouseEvent->mButton == MouseButton::eMiddle) ||
EventCausesClickEvents(*aMouseEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6109); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
")"); do { *((volatile int*)__null) = 6109; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6108 aMouseEvent->mButton == MouseButton::eMiddle) ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aMouseEvent->mMessage == ePointerAuxClick &&
aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents
(*aMouseEvent))>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!((aMouseEvent->mMessage == ePointerAuxClick
&& aMouseEvent->mButton == MouseButton::eMiddle) ||
EventCausesClickEvents(*aMouseEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6109); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
")"); do { *((volatile int*)__null) = 6109; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6109 EventCausesClickEvents(*aMouseEvent))do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aMouseEvent->mMessage == ePointerAuxClick &&
aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents
(*aMouseEvent))>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!((aMouseEvent->mMessage == ePointerAuxClick
&& aMouseEvent->mButton == MouseButton::eMiddle) ||
EventCausesClickEvents(*aMouseEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6109); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
")"); do { *((volatile int*)__null) = 6109; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6110 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6110); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 6110; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6111 MOZ_ASSERT(*aStatus != nsEventStatus_eConsumeNoDefault)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(*aStatus != nsEventStatus_eConsumeNoDefault))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6111); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault"
")"); do { *((volatile int*)__null) = 6111; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6112
6113 // Even if we're called twice or more for a mouse operation, we should
6114 // handle only once. Although mMultipleActionsPrevented may be set to
6115 // true by different event handler in the future, we can use it for now.
6116 if (aMouseEvent->mFlags.mMultipleActionsPrevented) {
6117 return NS_OK;
6118 }
6119 aMouseEvent->mFlags.mMultipleActionsPrevented = true;
6120
6121 RefPtr<Selection> selection;
6122 if (aEditorBase) {
6123 selection = aEditorBase->GetSelection();
6124 if (NS_WARN_IF(!selection)NS_warn_if_impl(!selection, "!selection", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6124)
) {
6125 return NS_ERROR_FAILURE;
6126 }
6127 } else {
6128 Document* document = aPresShell->GetDocument();
6129 if (NS_WARN_IF(!document)NS_warn_if_impl(!document, "!document", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6129)
) {
6130 return NS_ERROR_FAILURE;
6131 }
6132 selection = nsCopySupport::GetSelectionForCopy(document);
6133 if (NS_WARN_IF(!selection)NS_warn_if_impl(!selection, "!selection", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6133)
) {
6134 return NS_ERROR_FAILURE;
6135 }
6136
6137 const nsRange* range = selection->GetRangeAt(0);
6138 if (range) {
6139 nsINode* target = range->GetStartContainer();
6140 if (target && target->OwnerDoc()->IsInChromeDocShell()) {
6141 // In Chrome document, limit middle-click pasting to only the editor
6142 // because it looks odd if pasting works in the focused editor when you
6143 // middle-click toolbar or something which are far from the editor.
6144 // However, as DevTools especially Web Console module assumes that paste
6145 // event will be fired when middle-click even on not editor, don't limit
6146 // it.
6147 return NS_OK;
6148 }
6149 }
6150 }
6151
6152 // Don't modify selection here because we've already set caret to the point
6153 // at "mousedown" event.
6154
6155 nsIClipboard::ClipboardType clipboardType = nsIClipboard::kGlobalClipboard;
6156 nsCOMPtr<nsIClipboard> clipboardService =
6157 do_GetService("@mozilla.org/widget/clipboard;1");
6158 if (clipboardService && clipboardService->IsClipboardTypeSupported(
6159 nsIClipboard::kSelectionClipboard)) {
6160 clipboardType = nsIClipboard::kSelectionClipboard;
6161 }
6162
6163 // Fire ePaste event by ourselves since we need to dispatch "paste" event
6164 // even if the middle click event was consumed for compatibility with
6165 // Chromium.
6166 if (!nsCopySupport::FireClipboardEvent(ePaste, Some(clipboardType),
6167 aPresShell, selection)) {
6168 *aStatus = nsEventStatus_eConsumeNoDefault;
6169 return NS_OK;
6170 }
6171
6172 // Although we've fired "paste" event, there is no editor to accept the
6173 // clipboard content.
6174 if (!aEditorBase) {
6175 return NS_OK;
6176 }
6177
6178 // Check if the editor is still the good target to paste.
6179 if (aEditorBase->Destroyed() || aEditorBase->IsReadonly()) {
6180 // XXX Should we consume the event when the editor is readonly and/or
6181 // disabled?
6182 return NS_OK;
6183 }
6184
6185 // The selection may have been modified during reflow. Therefore, we
6186 // should adjust event target to pass IsAcceptableInputEvent().
6187 const nsRange* range = selection->GetRangeAt(0);
6188 if (!range) {
6189 return NS_OK;
6190 }
6191 WidgetMouseEvent mouseEvent(*aMouseEvent);
6192 mouseEvent.mOriginalTarget = range->GetStartContainer();
6193 if (NS_WARN_IF(!mouseEvent.mOriginalTarget)NS_warn_if_impl(!mouseEvent.mOriginalTarget, "!mouseEvent.mOriginalTarget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6193)
||
6194 !aEditorBase->IsAcceptableInputEvent(&mouseEvent)) {
6195 return NS_OK;
6196 }
6197
6198 // If Control key is pressed, we should paste clipboard content as
6199 // quotation. Otherwise, paste it as is.
6200 if (aMouseEvent->IsControl()) {
6201 DebugOnly<nsresult> rv = aEditorBase->PasteAsQuotationAsAction(
6202 clipboardType, EditorBase::DispatchPasteEvent::No);
6203 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to paste as quotation")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to paste as quotation"
, "NS_SUCCEEDED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6203); } } while (false)
;
6204 } else {
6205 DebugOnly<nsresult> rv = aEditorBase->PasteAsAction(
6206 clipboardType, EditorBase::DispatchPasteEvent::No);
6207 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to paste")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to paste", "NS_SUCCEEDED(rv)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6207); } } while (false)
;
6208 }
6209 *aStatus = nsEventStatus_eConsumeNoDefault;
6210
6211 return NS_OK;
6212}
6213
6214void EventStateManager::ConsumeInteractionData(
6215 Record<nsString, dom::InteractionData>& aInteractions) {
6216 OnTypingInteractionEnded();
6217
6218 aInteractions.Entries().Clear();
6219 auto newEntry = aInteractions.Entries().AppendElement();
6220 newEntry->mKey = u"Typing"_ns;
6221 newEntry->mValue = gTypingInteraction;
6222 gTypingInteraction = {};
6223}
6224
6225nsIFrame* EventStateManager::GetEventTarget() {
6226 PresShell* presShell;
6227 if (mCurrentTarget || !mPresContext ||
6228 !(presShell = mPresContext->GetPresShell())) {
6229 return mCurrentTarget;
6230 }
6231
6232 if (mCurrentTargetContent) {
6233 mCurrentTarget = mPresContext->GetPrimaryFrameFor(mCurrentTargetContent);
6234 if (mCurrentTarget) {
6235 return mCurrentTarget;
6236 }
6237 }
6238
6239 nsIFrame* frame = presShell->GetCurrentEventFrame();
6240 return (mCurrentTarget = frame);
6241}
6242
6243already_AddRefed<nsIContent> EventStateManager::GetEventTargetContent(
6244 WidgetEvent* aEvent) {
6245 if (aEvent && (aEvent->mMessage == eFocus || aEvent->mMessage == eBlur)) {
6246 nsCOMPtr<nsIContent> content = GetFocusedElement();
6247 return content.forget();
6248 }
6249
6250 if (mCurrentTargetContent) {
6251 nsCOMPtr<nsIContent> content = mCurrentTargetContent;
6252 return content.forget();
6253 }
6254
6255 nsCOMPtr<nsIContent> content;
6256 if (PresShell* presShell = mPresContext->GetPresShell()) {
6257 content = presShell->GetEventTargetContent(aEvent);
6258 }
6259
6260 // Some events here may set mCurrentTarget but not set the corresponding
6261 // event target in the PresShell.
6262 if (!content && mCurrentTarget) {
6263 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(content));
6264 }
6265
6266 return content.forget();
6267}
6268
6269static Element* GetLabelTarget(nsIContent* aPossibleLabel) {
6270 mozilla::dom::HTMLLabelElement* label =
6271 mozilla::dom::HTMLLabelElement::FromNode(aPossibleLabel);
6272 if (!label) return nullptr;
6273
6274 return label->GetLabeledElement();
6275}
6276
6277/* static */
6278inline void EventStateManager::DoStateChange(Element* aElement,
6279 ElementState aState,
6280 bool aAddState) {
6281 if (aAddState) {
6282 aElement->AddStates(aState);
6283 } else {
6284 aElement->RemoveStates(aState);
6285 }
6286}
6287
6288/* static */
6289inline void EventStateManager::DoStateChange(nsIContent* aContent,
6290 ElementState aState,
6291 bool aStateAdded) {
6292 if (aContent->IsElement()) {
6293 DoStateChange(aContent->AsElement(), aState, aStateAdded);
6294 }
6295}
6296
6297/* static */
6298void EventStateManager::UpdateAncestorState(nsIContent* aStartNode,
6299 nsIContent* aStopBefore,
6300 ElementState aState,
6301 bool aAddState) {
6302 for (; aStartNode && aStartNode != aStopBefore;
6303 aStartNode = aStartNode->GetFlattenedTreeParent()) {
6304 // We might be starting with a non-element (e.g. a text node) and
6305 // if someone is doing something weird might be ending with a
6306 // non-element too (e.g. a document fragment)
6307 if (!aStartNode->IsElement()) {
6308 continue;
6309 }
6310 Element* element = aStartNode->AsElement();
6311 DoStateChange(element, aState, aAddState);
6312 Element* labelTarget = GetLabelTarget(element);
6313 if (labelTarget) {
6314 DoStateChange(labelTarget, aState, aAddState);
6315 }
6316 }
6317
6318 if (aAddState) {
6319 // We might be in a situation where a node was in hover both
6320 // because it was hovered and because the label for it was
6321 // hovered, and while we stopped hovering the node the label is
6322 // still hovered. Or we might have had two nested labels for the
6323 // same node, and while one is no longer hovered the other still
6324 // is. In that situation, the label that's still hovered will be
6325 // aStopBefore or some ancestor of it, and the call we just made
6326 // to UpdateAncestorState with aAddState = false would have
6327 // removed the hover state from the node. But the node should
6328 // still be in hover state. To handle this situation we need to
6329 // keep walking up the tree and any time we find a label mark its
6330 // corresponding node as still in our state.
6331 for (; aStartNode; aStartNode = aStartNode->GetFlattenedTreeParent()) {
6332 if (!aStartNode->IsElement()) {
6333 continue;
6334 }
6335
6336 Element* labelTarget = GetLabelTarget(aStartNode->AsElement());
6337 if (labelTarget && !labelTarget->State().HasState(aState)) {
6338 DoStateChange(labelTarget, aState, true);
6339 }
6340 }
6341 }
6342}
6343
6344// static
6345bool CanContentHaveActiveState(nsIContent& aContent) {
6346 // Editable content can never become active since their default actions
6347 // are disabled. Watch out for editable content in native anonymous
6348 // subtrees though, as they belong to text controls.
6349 return !aContent.IsEditable() || aContent.IsInNativeAnonymousSubtree();
6350}
6351
6352bool EventStateManager::SetContentState(nsIContent* aContent,
6353 ElementState aState) {
6354 MOZ_ASSERT(ManagesState(aState), "Unexpected state")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ManagesState(aState))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ManagesState(aState)))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("ManagesState(aState)"
" (" "Unexpected state" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6354); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ManagesState(aState)"
") (" "Unexpected state" ")"); do { *((volatile int*)__null)
= 6354; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
6355
6356 nsCOMPtr<nsIContent> notifyContent1;
6357 nsCOMPtr<nsIContent> notifyContent2;
6358 bool updateAncestors;
6359
6360 if (aState == ElementState::HOVER || aState == ElementState::ACTIVE) {
6361 // Hover and active are hierarchical
6362 updateAncestors = true;
6363
6364 // check to see that this state is allowed by style. Check dragover too?
6365 // XXX Is this even what we want?
6366 if (mCurrentTarget &&
6367 mCurrentTarget->StyleUI()->UserInput() == StyleUserInput::None) {
6368 return false;
6369 }
6370
6371 if (aState == ElementState::ACTIVE) {
6372 if (aContent && !CanContentHaveActiveState(*aContent)) {
6373 aContent = nullptr;
6374 }
6375 if (aContent != mActiveContent) {
6376 notifyContent1 = aContent;
6377 notifyContent2 = mActiveContent;
6378 mActiveContent = aContent;
6379 }
6380 } else {
6381 NS_ASSERTION(aState == ElementState::HOVER, "How did that happen?")do { if (!(aState == ElementState::HOVER)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "How did that happen?", "aState == ElementState::HOVER", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6381); MOZ_PretendNoReturn(); } } while (0)
;
6382 nsIContent* newHover;
6383
6384 if (mPresContext->IsDynamic()) {
6385 newHover = aContent;
6386 } else {
6387 NS_ASSERTION(!aContent || aContent->GetComposedDoc() ==do { if (!(!aContent || aContent->GetComposedDoc() == mPresContext
->PresShell()->GetDocument())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected document", "!aContent || aContent->GetComposedDoc() == mPresContext->PresShell()->GetDocument()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6389); MOZ_PretendNoReturn(); } } while (0)
6388 mPresContext->PresShell()->GetDocument(),do { if (!(!aContent || aContent->GetComposedDoc() == mPresContext
->PresShell()->GetDocument())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected document", "!aContent || aContent->GetComposedDoc() == mPresContext->PresShell()->GetDocument()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6389); MOZ_PretendNoReturn(); } } while (0)
6389 "Unexpected document")do { if (!(!aContent || aContent->GetComposedDoc() == mPresContext
->PresShell()->GetDocument())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected document", "!aContent || aContent->GetComposedDoc() == mPresContext->PresShell()->GetDocument()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6389); MOZ_PretendNoReturn(); } } while (0)
;
6390 nsIFrame* frame = aContent ? aContent->GetPrimaryFrame() : nullptr;
6391 if (frame && nsLayoutUtils::IsViewportScrollbarFrame(frame)) {
6392 // The scrollbars of viewport should not ignore the hover state.
6393 // Because they are *not* the content of the web page.
6394 newHover = aContent;
6395 } else {
6396 // All contents of the web page should ignore the hover state.
6397 newHover = nullptr;
6398 }
6399 }
6400
6401 if (newHover != mHoverContent) {
6402 notifyContent1 = newHover;
6403 notifyContent2 = mHoverContent;
6404 mHoverContent = newHover;
6405 }
6406 }
6407 } else {
6408 updateAncestors = false;
6409 if (aState == ElementState::DRAGOVER) {
6410 if (aContent != sDragOverContent) {
6411 notifyContent1 = aContent;
6412 notifyContent2 = sDragOverContent;
6413 sDragOverContent = aContent;
6414 }
6415 } else if (aState == ElementState::URLTARGET) {
6416 if (aContent != mURLTargetContent) {
6417 notifyContent1 = aContent;
6418 notifyContent2 = mURLTargetContent;
6419 mURLTargetContent = aContent;
6420 }
6421 }
6422 }
6423
6424 // We need to keep track of which of notifyContent1 and notifyContent2 is
6425 // getting the state set and which is getting it unset. If both are
6426 // non-null, then notifyContent1 is having the state set and notifyContent2
6427 // is having it unset. But if one of them is null, we need to keep track of
6428 // the right thing for notifyContent1 explicitly.
6429 bool content1StateSet = true;
6430 if (!notifyContent1) {
6431 // This is ok because FindCommonAncestor wouldn't find anything
6432 // anyway if notifyContent1 is null.
6433 notifyContent1 = notifyContent2;
6434 notifyContent2 = nullptr;
6435 content1StateSet = false;
6436 }
6437
6438 if (notifyContent1 && mPresContext) {
6439 EnsureDocument(mPresContext);
6440 if (mDocument) {
6441 nsAutoScriptBlocker scriptBlocker;
6442
6443 if (updateAncestors) {
6444 nsCOMPtr<nsIContent> commonAncestor =
6445 FindCommonAncestor(notifyContent1, notifyContent2);
6446 if (notifyContent2) {
6447 // It's very important to first notify the state removal and
6448 // then the state addition, because due to labels it's
6449 // possible that we're removing state from some element but
6450 // then adding it again (say because mHoverContent changed
6451 // from a control to its label).
6452 UpdateAncestorState(notifyContent2, commonAncestor, aState, false);
6453 }
6454 UpdateAncestorState(notifyContent1, commonAncestor, aState,
6455 content1StateSet);
6456 } else {
6457 if (notifyContent2) {
6458 DoStateChange(notifyContent2, aState, false);
6459 }
6460 DoStateChange(notifyContent1, aState, content1StateSet);
6461 }
6462 }
6463 }
6464
6465 return true;
6466}
6467
6468void EventStateManager::RemoveNodeFromChainIfNeeded(ElementState aState,
6469 nsIContent* aContentRemoved,
6470 bool aNotify) {
6471 MOZ_ASSERT(aState == ElementState::HOVER || aState == ElementState::ACTIVE)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aState == ElementState::HOVER || aState == ElementState
::ACTIVE)>::isValid, "invalid assertion condition"); if ((
__builtin_expect(!!(!(!!(aState == ElementState::HOVER || aState
== ElementState::ACTIVE))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aState == ElementState::HOVER || aState == ElementState::ACTIVE"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6471); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aState == ElementState::HOVER || aState == ElementState::ACTIVE"
")"); do { *((volatile int*)__null) = 6471; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6472 if (!aContentRemoved->IsElement() ||
6473 !aContentRemoved->AsElement()->State().HasState(aState)) {
6474 return;
6475 }
6476
6477 nsCOMPtr<nsIContent>& leaf =
6478 aState == ElementState::HOVER ? mHoverContent : mActiveContent;
6479
6480 MOZ_ASSERT(leaf)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(leaf)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(leaf))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("leaf", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6480); AnnotateMozCrashReason("MOZ_ASSERT" "(" "leaf" ")");
do { *((volatile int*)__null) = 6480; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6481 // These two NS_ASSERTIONS below can fail for Shadow DOM sometimes, and it's
6482 // not clear how to best handle it, see
6483 // https://github.com/whatwg/html/issues/4795 and bug 1551621.
6484 NS_ASSERTION(do { if (!(nsContentUtils::ContentIsFlattenedTreeDescendantOf
(leaf, aContentRemoved))) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"Flat tree and active / hover chain got out of sync", "nsContentUtils::ContentIsFlattenedTreeDescendantOf(leaf, aContentRemoved)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6486); MOZ_PretendNoReturn(); } } while (0)
6485 nsContentUtils::ContentIsFlattenedTreeDescendantOf(leaf, aContentRemoved),do { if (!(nsContentUtils::ContentIsFlattenedTreeDescendantOf
(leaf, aContentRemoved))) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"Flat tree and active / hover chain got out of sync", "nsContentUtils::ContentIsFlattenedTreeDescendantOf(leaf, aContentRemoved)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6486); MOZ_PretendNoReturn(); } } while (0)
6486 "Flat tree and active / hover chain got out of sync")do { if (!(nsContentUtils::ContentIsFlattenedTreeDescendantOf
(leaf, aContentRemoved))) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"Flat tree and active / hover chain got out of sync", "nsContentUtils::ContentIsFlattenedTreeDescendantOf(leaf, aContentRemoved)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6486); MOZ_PretendNoReturn(); } } while (0)
;
6487
6488 nsIContent* newLeaf = aContentRemoved->GetFlattenedTreeParent();
6489 MOZ_ASSERT(!newLeaf || newLeaf->IsElement())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!newLeaf || newLeaf->IsElement())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!newLeaf || newLeaf->IsElement
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!newLeaf || newLeaf->IsElement()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6489); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!newLeaf || newLeaf->IsElement()"
")"); do { *((volatile int*)__null) = 6489; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6490 NS_ASSERTION(!newLeaf || newLeaf->AsElement()->State().HasState(aState),do { if (!(!newLeaf || newLeaf->AsElement()->State().HasState
(aState))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "State got out of sync because of shadow DOM"
, "!newLeaf || newLeaf->AsElement()->State().HasState(aState)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6491); MOZ_PretendNoReturn(); } } while (0)
6491 "State got out of sync because of shadow DOM")do { if (!(!newLeaf || newLeaf->AsElement()->State().HasState
(aState))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "State got out of sync because of shadow DOM"
, "!newLeaf || newLeaf->AsElement()->State().HasState(aState)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6491); MOZ_PretendNoReturn(); } } while (0)
;
6492 if (aNotify) {
6493 SetContentState(newLeaf, aState);
6494 } else {
6495 // We don't update the removed content's state here, since removing NAC
6496 // happens from layout and we don't really want to notify at that point or
6497 // what not.
6498 //
6499 // Also, NAC is not observable and NAC being removed will go away soon.
6500 leaf = newLeaf;
6501 }
6502 MOZ_ASSERT(leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(leaf == newLeaf || (aState == ElementState::ACTIVE &&
!leaf && !CanContentHaveActiveState(*newLeaf)))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(leaf == newLeaf || (aState == ElementState::ACTIVE &&
!leaf && !CanContentHaveActiveState(*newLeaf))))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf && !CanContentHaveActiveState(*newLeaf))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6503); AnnotateMozCrashReason("MOZ_ASSERT" "(" "leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf && !CanContentHaveActiveState(*newLeaf))"
")"); do { *((volatile int*)__null) = 6503; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6503 !CanContentHaveActiveState(*newLeaf)))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(leaf == newLeaf || (aState == ElementState::ACTIVE &&
!leaf && !CanContentHaveActiveState(*newLeaf)))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(leaf == newLeaf || (aState == ElementState::ACTIVE &&
!leaf && !CanContentHaveActiveState(*newLeaf))))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf && !CanContentHaveActiveState(*newLeaf))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6503); AnnotateMozCrashReason("MOZ_ASSERT" "(" "leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf && !CanContentHaveActiveState(*newLeaf))"
")"); do { *((volatile int*)__null) = 6503; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6504}
6505
6506void EventStateManager::NativeAnonymousContentRemoved(nsIContent* aContent) {
6507 MOZ_ASSERT(aContent->IsRootOfNativeAnonymousSubtree())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContent->IsRootOfNativeAnonymousSubtree())>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aContent->IsRootOfNativeAnonymousSubtree()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aContent->IsRootOfNativeAnonymousSubtree()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6507); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsRootOfNativeAnonymousSubtree()"
")"); do { *((volatile int*)__null) = 6507; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6508 RemoveNodeFromChainIfNeeded(ElementState::HOVER, aContent, false);
6509 RemoveNodeFromChainIfNeeded(ElementState::ACTIVE, aContent, false);
6510
6511 nsCOMPtr<nsIContent>& lastLeftMouseDownContent =
6512 mLastLeftMouseDownInfo.mLastMouseDownContent;
6513 if (lastLeftMouseDownContent &&
6514 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
6515 lastLeftMouseDownContent, aContent)) {
6516 lastLeftMouseDownContent = aContent->GetFlattenedTreeParent();
6517 }
6518
6519 nsCOMPtr<nsIContent>& lastMiddleMouseDownContent =
6520 mLastMiddleMouseDownInfo.mLastMouseDownContent;
6521 if (lastMiddleMouseDownContent &&
6522 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
6523 lastMiddleMouseDownContent, aContent)) {
6524 lastMiddleMouseDownContent = aContent->GetFlattenedTreeParent();
6525 }
6526
6527 nsCOMPtr<nsIContent>& lastRightMouseDownContent =
6528 mLastRightMouseDownInfo.mLastMouseDownContent;
6529 if (lastRightMouseDownContent &&
6530 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
6531 lastRightMouseDownContent, aContent)) {
6532 lastRightMouseDownContent = aContent->GetFlattenedTreeParent();
6533 }
6534}
6535
6536void EventStateManager::ContentRemoved(Document* aDocument,
6537 nsIContent* aContent) {
6538 /*
6539 * Anchor and area elements when focused or hovered might make the UI to show
6540 * the current link. We want to make sure that the UI gets informed when they
6541 * are actually removed from the DOM.
6542 */
6543 if (aContent->IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area) &&
6544 (aContent->AsElement()->State().HasAtLeastOneOfStates(
6545 ElementState::FOCUS | ElementState::HOVER))) {
6546 Element* element = aContent->AsElement();
6547 element->LeaveLink(element->GetPresContext(Element::eForComposedDoc));
6548 }
6549
6550 if (aContent->IsElement()) {
6551 if (RefPtr<nsPresContext> presContext = mPresContext) {
6552 IMEStateManager::OnRemoveContent(*presContext,
6553 MOZ_KnownLive(*aContent->AsElement())(*aContent->AsElement()));
6554 }
6555 WheelTransaction::OnRemoveElement(aContent);
6556 }
6557
6558 // inform the focus manager that the content is being removed. If this
6559 // content is focused, the focus will be removed without firing events.
6560 if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
6561 fm->ContentRemoved(aDocument, aContent);
6562 }
6563
6564 RemoveNodeFromChainIfNeeded(ElementState::HOVER, aContent, true);
6565 RemoveNodeFromChainIfNeeded(ElementState::ACTIVE, aContent, true);
6566
6567 if (sDragOverContent &&
6568 sDragOverContent->OwnerDoc() == aContent->OwnerDoc() &&
6569 nsContentUtils::ContentIsFlattenedTreeDescendantOf(sDragOverContent,
6570 aContent)) {
6571 sDragOverContent = nullptr;
6572 }
6573
6574 PointerEventHandler::ReleaseIfCaptureByDescendant(aContent);
6575
6576 if (mMouseEnterLeaveHelper) {
6577 const bool hadMouseOutTarget =
6578 mMouseEnterLeaveHelper->GetOutEventTarget() != nullptr;
6579 mMouseEnterLeaveHelper->ContentRemoved(*aContent);
6580 // If we lose the mouseout target, we need to dispatch mouseover on an
6581 // ancestor. For ensuring the chance to do it before next user input, we
6582 // need a synthetic mouse move.
6583 if (hadMouseOutTarget && !mMouseEnterLeaveHelper->GetOutEventTarget()) {
6584 if (PresShell* presShell =
6585 mPresContext ? mPresContext->GetPresShell() : nullptr) {
6586 presShell->SynthesizeMouseMove(false);
6587 }
6588 }
6589 }
6590 for (const auto& entry : mPointersEnterLeaveHelper) {
6591 if (entry.GetData()) {
6592 entry.GetData()->ContentRemoved(*aContent);
6593 }
6594 }
6595}
6596
6597void EventStateManager::TextControlRootWillBeRemoved(
6598 TextControlElement& aTextControlElement) {
6599 if (!mGestureDownInTextControl || !mGestureDownFrameOwner ||
6600 !mGestureDownFrameOwner->IsInNativeAnonymousSubtree()) {
6601 return;
6602 }
6603 // If we track gesture to start drag in aTextControlElement, we should keep
6604 // tracking it with aTextContrlElement itself for now because this may be
6605 // caused by reframing aTextControlElement which may not be intended by the
6606 // user.
6607 if (&aTextControlElement ==
6608 mGestureDownFrameOwner
6609 ->GetClosestNativeAnonymousSubtreeRootParentOrHost()) {
6610 mGestureDownFrameOwner = &aTextControlElement;
6611 }
6612}
6613
6614void EventStateManager::TextControlRootAdded(
6615 Element& aAnonymousDivElement, TextControlElement& aTextControlElement) {
6616 if (!mGestureDownInTextControl ||
6617 mGestureDownFrameOwner != &aTextControlElement) {
6618 return;
6619 }
6620 // If we track gesture to start drag in aTextControlElement, but the frame
6621 // owner is the text control element itself, the anonymous nodes in it are
6622 // recreated by a reframe. If so, we should keep tracking it with the
6623 // recreated native anonymous node.
6624 mGestureDownFrameOwner =
6625 aAnonymousDivElement.GetFirstChild()
6626 ? aAnonymousDivElement.GetFirstChild()
6627 : static_cast<nsIContent*>(&aAnonymousDivElement);
6628}
6629
6630bool EventStateManager::EventStatusOK(WidgetGUIEvent* aEvent) {
6631 return !(aEvent->mMessage == eMouseDown &&
6632 aEvent->AsMouseEvent()->mButton == MouseButton::ePrimary &&
6633 !sNormalLMouseEventInProcess);
6634}
6635
6636//-------------------------------------------
6637// Access Key Registration
6638//-------------------------------------------
6639void EventStateManager::RegisterAccessKey(Element* aElement, uint32_t aKey) {
6640 if (aElement && !mAccessKeys.Contains(aElement)) {
6641 mAccessKeys.AppendObject(aElement);
6642 }
6643}
6644
6645void EventStateManager::UnregisterAccessKey(Element* aElement, uint32_t aKey) {
6646 if (aElement) {
6647 mAccessKeys.RemoveObject(aElement);
6648 }
6649}
6650
6651uint32_t EventStateManager::GetRegisteredAccessKey(Element* aElement) {
6652 MOZ_ASSERT(aElement)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aElement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aElement))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aElement", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6652); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aElement" ")"
); do { *((volatile int*)__null) = 6652; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6653
6654 if (!mAccessKeys.Contains(aElement)) {
6655 return 0;
6656 }
6657
6658 nsAutoString accessKey;
6659 aElement->GetAttr(nsGkAtoms::accesskey, accessKey);
6660 return accessKey.First();
6661}
6662
6663void EventStateManager::EnsureDocument(nsPresContext* aPresContext) {
6664 if (!mDocument) mDocument = aPresContext->Document();
6665}
6666
6667void EventStateManager::FlushLayout(nsPresContext* aPresContext) {
6668 MOZ_ASSERT(aPresContext, "nullptr ptr")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresContext))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPresContext" " ("
"nullptr ptr" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6668); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresContext"
") (" "nullptr ptr" ")"); do { *((volatile int*)__null) = 6668
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
6669 if (RefPtr<PresShell> presShell = aPresContext->GetPresShell()) {
6670 presShell->FlushPendingNotifications(FlushType::InterruptibleLayout);
6671 }
6672}
6673
6674Element* EventStateManager::GetFocusedElement() {
6675 nsFocusManager* fm = nsFocusManager::GetFocusManager();
6676 EnsureDocument(mPresContext);
6677 if (!fm || !mDocument) {
6678 return nullptr;
6679 }
6680
6681 nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
6682 return nsFocusManager::GetFocusedDescendant(
6683 mDocument->GetWindow(), nsFocusManager::eOnlyCurrentWindow,
6684 getter_AddRefs(focusedWindow));
6685}
6686
6687//-------------------------------------------------------
6688// Return true if the docshell is visible
6689
6690bool EventStateManager::IsShellVisible(nsIDocShell* aShell) {
6691 NS_ASSERTION(aShell, "docshell is null")do { if (!(aShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "docshell is null"
, "aShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6691); MOZ_PretendNoReturn(); } } while (0)
;
6692
6693 nsCOMPtr<nsIBaseWindow> basewin = do_QueryInterface(aShell);
6694 if (!basewin) return true;
6695
6696 bool isVisible = true;
6697 basewin->GetVisibility(&isVisible);
6698
6699 // We should be doing some additional checks here so that
6700 // we don't tab into hidden tabs of tabbrowser. -bryner
6701
6702 return isVisible;
6703}
6704
6705nsresult EventStateManager::DoContentCommandEvent(
6706 WidgetContentCommandEvent* aEvent) {
6707 EnsureDocument(mPresContext);
6708 NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(mDocument)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mDocument" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6708); return NS_ERROR_FAILURE; } } while (false)
;
6709 nsCOMPtr<nsPIDOMWindowOuter> window(mDocument->GetWindow());
6710 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(window)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "window" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6710); return NS_ERROR_FAILURE; } } while (false)
;
6711
6712 nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
6713 NS_ENSURE_TRUE(root, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(root)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "root" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6713); return NS_ERROR_FAILURE; } } while (false)
;
6714 const char* cmd;
6715 switch (aEvent->mMessage) {
6716 case eContentCommandCut:
6717 cmd = "cmd_cut";
6718 break;
6719 case eContentCommandCopy:
6720 cmd = "cmd_copy";
6721 break;
6722 case eContentCommandPaste:
6723 cmd = "cmd_paste";
6724 break;
6725 case eContentCommandDelete:
6726 cmd = "cmd_delete";
6727 break;
6728 case eContentCommandUndo:
6729 cmd = "cmd_undo";
6730 break;
6731 case eContentCommandRedo:
6732 cmd = "cmd_redo";
6733 break;
6734 case eContentCommandPasteTransferable:
6735 cmd = "cmd_pasteTransferable";
6736 break;
6737 case eContentCommandLookUpDictionary:
6738 cmd = "cmd_lookUpDictionary";
6739 break;
6740 default:
6741 return NS_ERROR_NOT_IMPLEMENTED;
6742 }
6743 // If user tries to do something, user must try to do it in visible window.
6744 // So, let's retrieve controller of visible window.
6745 nsCOMPtr<nsIController> controller;
6746 nsresult rv =
6747 root->GetControllerForCommand(cmd, true, getter_AddRefs(controller));
6748 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6748); return rv; } } while (false)
;
6749 if (!controller) {
6750 // When GetControllerForCommand succeeded but there is no controller, the
6751 // command isn't supported.
6752 aEvent->mIsEnabled = false;
6753 } else {
6754 bool canDoIt;
6755 rv = controller->IsCommandEnabled(cmd, &canDoIt);
6756 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6756); return rv; } } while (false)
;
6757 aEvent->mIsEnabled = canDoIt;
6758 if (canDoIt && !aEvent->mOnlyEnabledCheck) {
6759 switch (aEvent->mMessage) {
6760 case eContentCommandPasteTransferable: {
6761 BrowserParent* remote = BrowserParent::GetFocused();
6762 if (remote) {
6763 IPCTransferable ipcTransferable;
6764 nsContentUtils::TransferableToIPCTransferable(
6765 aEvent->mTransferable, &ipcTransferable, false,
6766 remote->Manager());
6767 remote->SendPasteTransferable(std::move(ipcTransferable));
6768 rv = NS_OK;
6769 } else {
6770 nsCOMPtr<nsICommandController> commandController =
6771 do_QueryInterface(controller);
6772 NS_ENSURE_STATE(commandController)do { if ((__builtin_expect(!!(!(commandController)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "commandController" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6772); return NS_ERROR_UNEXPECTED; } } while (false)
;
6773
6774 RefPtr<nsCommandParams> params = new nsCommandParams();
6775 rv = params->SetISupports("transferable", aEvent->mTransferable);
6776 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6776)
) {
6777 return rv;
6778 }
6779 rv = commandController->DoCommandWithParams(cmd, params);
6780 }
6781 break;
6782 }
6783
6784 case eContentCommandLookUpDictionary: {
6785 nsCOMPtr<nsICommandController> commandController =
6786 do_QueryInterface(controller);
6787 if (NS_WARN_IF(!commandController)NS_warn_if_impl(!commandController, "!commandController", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6787)
) {
6788 return NS_ERROR_FAILURE;
6789 }
6790
6791 RefPtr<nsCommandParams> params = new nsCommandParams();
6792 rv = params->SetInt("x", aEvent->mRefPoint.x);
6793 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6793)
) {
6794 return rv;
6795 }
6796
6797 rv = params->SetInt("y", aEvent->mRefPoint.y);
6798 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6798)
) {
6799 return rv;
6800 }
6801
6802 rv = commandController->DoCommandWithParams(cmd, params);
6803 break;
6804 }
6805
6806 default:
6807 rv = controller->DoCommand(cmd);
6808 break;
6809 }
6810 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6810); return rv; } } while (false)
;
6811 }
6812 }
6813 aEvent->mSucceeded = true;
6814 return NS_OK;
6815}
6816
6817nsresult EventStateManager::DoContentCommandInsertTextEvent(
6818 WidgetContentCommandEvent* aEvent) {
6819 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6819); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 6819; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6820 MOZ_ASSERT(aEvent->mMessage == eContentCommandInsertText)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eContentCommandInsertText)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aEvent->mMessage == eContentCommandInsertText))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eContentCommandInsertText"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6820); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eContentCommandInsertText"
")"); do { *((volatile int*)__null) = 6820; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6821 MOZ_DIAGNOSTIC_ASSERT(aEvent->mString.isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mString.isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mString.isSome())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->mString.isSome()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6821); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aEvent->mString.isSome()"
")"); do { *((volatile int*)__null) = 6821; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6822 MOZ_DIAGNOSTIC_ASSERT(!aEvent->mString.ref().IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEvent->mString.ref().IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aEvent->mString.ref().IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aEvent->mString.ref().IsEmpty()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6822); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!aEvent->mString.ref().IsEmpty()"
")"); do { *((volatile int*)__null) = 6822; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6823
6824 aEvent->mIsEnabled = false;
6825 aEvent->mSucceeded = false;
6826
6827 NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(mPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6827); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
6828
6829 if (XRE_IsParentProcess()) {
6830 // Handle it in focused content process if there is.
6831 if (BrowserParent* remote = BrowserParent::GetFocused()) {
6832 remote->SendInsertText(aEvent->mString.ref());
6833 aEvent->mIsEnabled = true; // XXX it can be a lie...
6834 aEvent->mSucceeded = true;
6835 return NS_OK;
6836 }
6837 }
6838
6839 // If there is no active editor in this process, we should treat the command
6840 // is disabled.
6841 RefPtr<EditorBase> activeEditor =
6842 nsContentUtils::GetActiveEditor(mPresContext);
6843 if (!activeEditor) {
6844 aEvent->mSucceeded = true;
6845 return NS_OK;
6846 }
6847
6848 nsresult rv = activeEditor->InsertTextAsAction(aEvent->mString.ref());
6849 aEvent->mIsEnabled = rv != NS_SUCCESS_DOM_NO_OPERATION;
6850 aEvent->mSucceeded = NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)));
6851 return NS_OK;
6852}
6853
6854nsresult EventStateManager::DoContentCommandReplaceTextEvent(
6855 WidgetContentCommandEvent* aEvent) {
6856 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6856); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 6856; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6857 MOZ_ASSERT(aEvent->mMessage == eContentCommandReplaceText)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eContentCommandReplaceText)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aEvent->mMessage == eContentCommandReplaceText)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eContentCommandReplaceText"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6857); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eContentCommandReplaceText"
")"); do { *((volatile int*)__null) = 6857; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6858 MOZ_DIAGNOSTIC_ASSERT(aEvent->mString.isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mString.isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mString.isSome())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->mString.isSome()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6858); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aEvent->mString.isSome()"
")"); do { *((volatile int*)__null) = 6858; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6859 MOZ_DIAGNOSTIC_ASSERT(!aEvent->mString.ref().IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEvent->mString.ref().IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aEvent->mString.ref().IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aEvent->mString.ref().IsEmpty()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6859); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!aEvent->mString.ref().IsEmpty()"
")"); do { *((volatile int*)__null) = 6859; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6860
6861 aEvent->mIsEnabled = false;
6862 aEvent->mSucceeded = false;
6863
6864 NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(mPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6864); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
6865
6866 if (XRE_IsParentProcess()) {
6867 // Handle it in focused content process if there is.
6868 if (BrowserParent* remote = BrowserParent::GetFocused()) {
6869 Unused << remote->SendReplaceText(
6870 aEvent->mSelection.mReplaceSrcString, aEvent->mString.ref(),
6871 aEvent->mSelection.mOffset, aEvent->mSelection.mPreventSetSelection);
6872 aEvent->mIsEnabled = true; // XXX it can be a lie...
6873 aEvent->mSucceeded = true;
6874 return NS_OK;
6875 }
6876 }
6877
6878 // If there is no active editor in this process, we should treat the command
6879 // is disabled.
6880 RefPtr<EditorBase> activeEditor =
6881 nsContentUtils::GetActiveEditor(mPresContext);
6882 if (NS_WARN_IF(!activeEditor)NS_warn_if_impl(!activeEditor, "!activeEditor", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6882)
) {
6883 aEvent->mSucceeded = true;
6884 return NS_OK;
6885 }
6886
6887 RefPtr<TextComposition> composition =
6888 IMEStateManager::GetTextCompositionFor(mPresContext);
6889 if (NS_WARN_IF(composition)NS_warn_if_impl(composition, "composition", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6889)
) {
6890 // We don't support replace text action during composition.
6891 aEvent->mSucceeded = true;
6892 return NS_OK;
6893 }
6894
6895 ContentEventHandler handler(mPresContext);
6896 RefPtr<nsRange> range = handler.GetRangeFromFlatTextOffset(
6897 aEvent, aEvent->mSelection.mOffset,
6898 aEvent->mSelection.mReplaceSrcString.Length());
6899 if (NS_WARN_IF(!range)NS_warn_if_impl(!range, "!range", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6899)
) {
6900 aEvent->mSucceeded = false;
6901 return NS_OK;
6902 }
6903
6904 // If original replacement text isn't matched with selection text, throws
6905 // error.
6906 nsAutoString targetStr;
6907 nsresult rv = handler.GenerateFlatTextContent(range, targetStr);
6908 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6908)
) {
6909 aEvent->mSucceeded = false;
6910 return NS_OK;
6911 }
6912 if (!aEvent->mSelection.mReplaceSrcString.Equals(targetStr)) {
6913 aEvent->mSucceeded = false;
6914 return NS_OK;
6915 }
6916
6917 rv = activeEditor->ReplaceTextAsAction(
6918 aEvent->mString.ref(), range,
6919 TextEditor::AllowBeforeInputEventCancelable::Yes,
6920 aEvent->mSelection.mPreventSetSelection
6921 ? EditorBase::PreventSetSelection::Yes
6922 : EditorBase::PreventSetSelection::No);
6923 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6923)
) {
6924 aEvent->mSucceeded = false;
6925 return NS_OK;
6926 }
6927
6928 aEvent->mIsEnabled = rv != NS_SUCCESS_DOM_NO_OPERATION;
6929 aEvent->mSucceeded = true;
6930 return NS_OK;
6931}
6932
6933nsresult EventStateManager::DoContentCommandScrollEvent(
6934 WidgetContentCommandEvent* aEvent) {
6935 NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(mPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6935); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
6936 PresShell* presShell = mPresContext->GetPresShell();
6937 NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(presShell)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "presShell" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6937); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
6938 NS_ENSURE_TRUE(aEvent->mScroll.mAmount != 0, NS_ERROR_INVALID_ARG)do { if ((__builtin_expect(!!(!(aEvent->mScroll.mAmount !=
0)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE("
"aEvent->mScroll.mAmount != 0" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6938); return NS_ERROR_INVALID_ARG; } } while (false)
;
6939
6940 ScrollUnit scrollUnit;
6941 switch (aEvent->mScroll.mUnit) {
6942 case WidgetContentCommandEvent::eCmdScrollUnit_Line:
6943 scrollUnit = ScrollUnit::LINES;
6944 break;
6945 case WidgetContentCommandEvent::eCmdScrollUnit_Page:
6946 scrollUnit = ScrollUnit::PAGES;
6947 break;
6948 case WidgetContentCommandEvent::eCmdScrollUnit_Whole:
6949 scrollUnit = ScrollUnit::WHOLE;
6950 break;
6951 default:
6952 return NS_ERROR_INVALID_ARG;
6953 }
6954
6955 aEvent->mSucceeded = true;
6956
6957 ScrollContainerFrame* sf =
6958 presShell->GetScrollContainerFrameToScroll(layers::EitherScrollDirection);
6959 aEvent->mIsEnabled =
6960 sf ? (aEvent->mScroll.mIsHorizontal ? WheelHandlingUtils::CanScrollOn(
6961 sf, aEvent->mScroll.mAmount, 0)
6962 : WheelHandlingUtils::CanScrollOn(
6963 sf, 0, aEvent->mScroll.mAmount))
6964 : false;
6965
6966 if (!aEvent->mIsEnabled || aEvent->mOnlyEnabledCheck) {
6967 return NS_OK;
6968 }
6969
6970 nsIntPoint pt(0, 0);
6971 if (aEvent->mScroll.mIsHorizontal) {
6972 pt.x = aEvent->mScroll.mAmount;
6973 } else {
6974 pt.y = aEvent->mScroll.mAmount;
6975 }
6976
6977 // The caller may want synchronous scrolling.
6978 sf->ScrollBy(pt, scrollUnit, ScrollMode::Instant);
6979 return NS_OK;
6980}
6981
6982void EventStateManager::SetActiveManager(EventStateManager* aNewESM,
6983 nsIContent* aContent) {
6984 if (sActiveESM && aNewESM != sActiveESM) {
6985 sActiveESM->SetContentState(nullptr, ElementState::ACTIVE);
6986 }
6987 sActiveESM = aNewESM;
6988 if (sActiveESM && aContent) {
6989 sActiveESM->SetContentState(aContent, ElementState::ACTIVE);
6990 }
6991}
6992
6993void EventStateManager::ClearGlobalActiveContent(EventStateManager* aClearer) {
6994 if (aClearer) {
6995 aClearer->SetContentState(nullptr, ElementState::ACTIVE);
6996 if (sDragOverContent) {
6997 aClearer->SetContentState(nullptr, ElementState::DRAGOVER);
6998 }
6999 }
7000 if (sActiveESM && aClearer != sActiveESM) {
7001 sActiveESM->SetContentState(nullptr, ElementState::ACTIVE);
7002 }
7003 sActiveESM = nullptr;
7004}
7005
7006/******************************************************************/
7007/* mozilla::EventStateManager::DeltaAccumulator */
7008/******************************************************************/
7009
7010void EventStateManager::DeltaAccumulator::InitLineOrPageDelta(
7011 nsIFrame* aTargetFrame, EventStateManager* aESM, WidgetWheelEvent* aEvent) {
7012 MOZ_ASSERT(aESM)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aESM)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aESM))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aESM", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7012); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aESM" ")");
do { *((volatile int*)__null) = 7012; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7013 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7013); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 7013; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7014
7015 // Reset if the previous wheel event is too old.
7016 if (!mLastTime.IsNull()) {
7017 TimeDuration duration = TimeStamp::Now() - mLastTime;
7018 if (duration.ToMilliseconds() >
7019 StaticPrefs::mousewheel_transaction_timeout()) {
7020 Reset();
7021 }
7022 }
7023 // If we have accumulated delta, we may need to reset it.
7024 if (IsInTransaction()) {
7025 // If wheel event type is changed, reset the values.
7026 if (mHandlingDeltaMode != aEvent->mDeltaMode ||
7027 mIsNoLineOrPageDeltaDevice != aEvent->mIsNoLineOrPageDelta) {
7028 Reset();
7029 } else {
7030 // If the delta direction is changed, we should reset only the
7031 // accumulated values.
7032 if (mX && aEvent->mDeltaX && ((aEvent->mDeltaX > 0.0) != (mX > 0.0))) {
7033 mX = mPendingScrollAmountX = 0.0;
7034 }
7035 if (mY && aEvent->mDeltaY && ((aEvent->mDeltaY > 0.0) != (mY > 0.0))) {
7036 mY = mPendingScrollAmountY = 0.0;
7037 }
7038 }
7039 }
7040
7041 mHandlingDeltaMode = aEvent->mDeltaMode;
7042 mIsNoLineOrPageDeltaDevice = aEvent->mIsNoLineOrPageDelta;
7043
7044 {
7045 ScrollContainerFrame* scrollTarget = aESM->ComputeScrollTarget(
7046 aTargetFrame, aEvent, COMPUTE_DEFAULT_ACTION_TARGET);
7047 nsPresContext* pc = scrollTarget ? scrollTarget->PresContext()
7048 : aTargetFrame->PresContext();
7049 aEvent->mScrollAmount = aESM->GetScrollAmount(pc, aEvent, scrollTarget);
7050 }
7051
7052 // If it's handling neither a device that does not provide line or page deltas
7053 // nor delta values multiplied by prefs, we must not modify lineOrPageDelta
7054 // values.
7055 // TODO(emilio): Does this care about overridden scroll speed?
7056 if (!mIsNoLineOrPageDeltaDevice &&
7057 !EventStateManager::WheelPrefs::GetInstance()
7058 ->NeedToComputeLineOrPageDelta(aEvent)) {
7059 // Set the delta values to mX and mY. They would be used when above block
7060 // resets mX/mY/mPendingScrollAmountX/mPendingScrollAmountY if the direction
7061 // is changed.
7062 // NOTE: We shouldn't accumulate the delta values, it might could cause
7063 // overflow even though it's not a realistic situation.
7064 if (aEvent->mDeltaX) {
7065 mX = aEvent->mDeltaX;
7066 }
7067 if (aEvent->mDeltaY) {
7068 mY = aEvent->mDeltaY;
7069 }
7070 mLastTime = TimeStamp::Now();
7071 return;
7072 }
7073
7074 mX += aEvent->mDeltaX;
7075 mY += aEvent->mDeltaY;
7076
7077 if (mHandlingDeltaMode == WheelEvent_Binding::DOM_DELTA_PIXEL) {
7078 // Records pixel delta values and init mLineOrPageDeltaX and
7079 // mLineOrPageDeltaY for wheel events which are caused by pixel only
7080 // devices. Ignore mouse wheel transaction for computing this. The
7081 // lineOrPageDelta values will be used by dispatching legacy
7082 // eMouseScrollEventClass (DOMMouseScroll) but not be used for scrolling
7083 // of default action. The transaction should be used only for the default
7084 // action.
7085 auto scrollAmountInCSSPixels =
7086 CSSIntSize::FromAppUnitsRounded(aEvent->mScrollAmount);
7087
7088 aEvent->mLineOrPageDeltaX = RoundDown(mX) / scrollAmountInCSSPixels.width;
7089 aEvent->mLineOrPageDeltaY = RoundDown(mY) / scrollAmountInCSSPixels.height;
7090
7091 mX -= aEvent->mLineOrPageDeltaX * scrollAmountInCSSPixels.width;
7092 mY -= aEvent->mLineOrPageDeltaY * scrollAmountInCSSPixels.height;
7093 } else {
7094 aEvent->mLineOrPageDeltaX = RoundDown(mX);
7095 aEvent->mLineOrPageDeltaY = RoundDown(mY);
7096 mX -= aEvent->mLineOrPageDeltaX;
7097 mY -= aEvent->mLineOrPageDeltaY;
7098 }
7099
7100 mLastTime = TimeStamp::Now();
7101}
7102
7103void EventStateManager::DeltaAccumulator::Reset() {
7104 mX = mY = 0.0;
7105 mPendingScrollAmountX = mPendingScrollAmountY = 0.0;
7106 mHandlingDeltaMode = UINT32_MAX(4294967295U);
7107 mIsNoLineOrPageDeltaDevice = false;
7108}
7109
7110nsIntPoint
7111EventStateManager::DeltaAccumulator::ComputeScrollAmountForDefaultAction(
7112 WidgetWheelEvent* aEvent, const nsIntSize& aScrollAmountInDevPixels) {
7113 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7113); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 7113; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7114
7115 DeltaValues acceleratedDelta = WheelTransaction::AccelerateWheelDelta(aEvent);
7116
7117 nsIntPoint result(0, 0);
7118 if (aEvent->mDeltaMode == WheelEvent_Binding::DOM_DELTA_PIXEL) {
7119 mPendingScrollAmountX += acceleratedDelta.deltaX;
7120 mPendingScrollAmountY += acceleratedDelta.deltaY;
7121 } else {
7122 mPendingScrollAmountX +=
7123 aScrollAmountInDevPixels.width * acceleratedDelta.deltaX;
7124 mPendingScrollAmountY +=
7125 aScrollAmountInDevPixels.height * acceleratedDelta.deltaY;
7126 }
7127 result.x = RoundDown(mPendingScrollAmountX);
7128 result.y = RoundDown(mPendingScrollAmountY);
7129 mPendingScrollAmountX -= result.x;
7130 mPendingScrollAmountY -= result.y;
7131
7132 return result;
7133}
7134
7135/******************************************************************/
7136/* mozilla::EventStateManager::WheelPrefs */
7137/******************************************************************/
7138
7139// static
7140EventStateManager::WheelPrefs* EventStateManager::WheelPrefs::GetInstance() {
7141 if (!sInstance) {
7142 sInstance = new WheelPrefs();
7143 }
7144 return sInstance;
7145}
7146
7147// static
7148void EventStateManager::WheelPrefs::Shutdown() {
7149 delete sInstance;
7150 sInstance = nullptr;
7151}
7152
7153// static
7154void EventStateManager::WheelPrefs::OnPrefChanged(const char* aPrefName,
7155 void* aClosure) {
7156 // forget all prefs, it's not problem for performance.
7157 sInstance->Reset();
7158 DeltaAccumulator::GetInstance()->Reset();
7159}
7160
7161EventStateManager::WheelPrefs::WheelPrefs() {
7162 Reset();
7163 Preferences::RegisterPrefixCallback(OnPrefChanged, "mousewheel.");
7164}
7165
7166EventStateManager::WheelPrefs::~WheelPrefs() {
7167 Preferences::UnregisterPrefixCallback(OnPrefChanged, "mousewheel.");
7168}
7169
7170void EventStateManager::WheelPrefs::Reset() { memset(mInit, 0, sizeof(mInit)); }
7171
7172EventStateManager::WheelPrefs::Index EventStateManager::WheelPrefs::GetIndexFor(
7173 const WidgetWheelEvent* aEvent) {
7174 if (!aEvent) {
7175 return INDEX_DEFAULT;
7176 }
7177
7178 Modifiers modifiers = (aEvent->mModifiers & (MODIFIER_ALT | MODIFIER_CONTROL |
7179 MODIFIER_META | MODIFIER_SHIFT));
7180
7181 switch (modifiers) {
7182 case MODIFIER_ALT:
7183 return INDEX_ALT;
7184 case MODIFIER_CONTROL:
7185 return INDEX_CONTROL;
7186 case MODIFIER_META:
7187 return INDEX_META;
7188 case MODIFIER_SHIFT:
7189 return INDEX_SHIFT;
7190 default:
7191 // If two or more modifier keys are pressed, we should use default
7192 // settings.
7193 return INDEX_DEFAULT;
7194 }
7195}
7196
7197void EventStateManager::WheelPrefs::GetBasePrefName(
7198 EventStateManager::WheelPrefs::Index aIndex, nsACString& aBasePrefName) {
7199 aBasePrefName.AssignLiteral("mousewheel.");
7200 switch (aIndex) {
7201 case INDEX_ALT:
7202 aBasePrefName.AppendLiteral("with_alt.");
7203 break;
7204 case INDEX_CONTROL:
7205 aBasePrefName.AppendLiteral("with_control.");
7206 break;
7207 case INDEX_META:
7208 aBasePrefName.AppendLiteral("with_meta.");
7209 break;
7210 case INDEX_SHIFT:
7211 aBasePrefName.AppendLiteral("with_shift.");
7212 break;
7213 case INDEX_DEFAULT:
7214 default:
7215 aBasePrefName.AppendLiteral("default.");
7216 break;
7217 }
7218}
7219
7220void EventStateManager::WheelPrefs::Init(
7221 EventStateManager::WheelPrefs::Index aIndex) {
7222 if (mInit[aIndex]) {
7223 return;
7224 }
7225 mInit[aIndex] = true;
7226
7227 nsAutoCString basePrefName;
7228 GetBasePrefName(aIndex, basePrefName);
7229
7230 nsAutoCString prefNameX(basePrefName);
7231 prefNameX.AppendLiteral("delta_multiplier_x");
7232 mMultiplierX[aIndex] =
7233 static_cast<double>(Preferences::GetInt(prefNameX.get(), 100)) / 100;
7234
7235 nsAutoCString prefNameY(basePrefName);
7236 prefNameY.AppendLiteral("delta_multiplier_y");
7237 mMultiplierY[aIndex] =
7238 static_cast<double>(Preferences::GetInt(prefNameY.get(), 100)) / 100;
7239
7240 nsAutoCString prefNameZ(basePrefName);
7241 prefNameZ.AppendLiteral("delta_multiplier_z");
7242 mMultiplierZ[aIndex] =
7243 static_cast<double>(Preferences::GetInt(prefNameZ.get(), 100)) / 100;
7244
7245 nsAutoCString prefNameAction(basePrefName);
7246 prefNameAction.AppendLiteral("action");
7247 int32_t action = Preferences::GetInt(prefNameAction.get(), ACTION_SCROLL);
7248 if (action < int32_t(ACTION_NONE) || action > int32_t(ACTION_LAST)) {
7249 NS_WARNING("Unsupported action pref value, replaced with 'Scroll'.")NS_DebugBreak(NS_DEBUG_WARNING, "Unsupported action pref value, replaced with 'Scroll'."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7249)
;
7250 action = ACTION_SCROLL;
7251 }
7252 mActions[aIndex] = static_cast<Action>(action);
7253
7254 // Compute action values overridden by .override_x pref.
7255 // At present, override is possible only for the x-direction
7256 // because this pref is introduced mainly for tilt wheels.
7257 // Note that ACTION_HORIZONTALIZED_SCROLL isn't a valid value for this pref
7258 // because it affects only to deltaY.
7259 prefNameAction.AppendLiteral(".override_x");
7260 int32_t actionOverrideX = Preferences::GetInt(prefNameAction.get(), -1);
7261 if (actionOverrideX < -1 || actionOverrideX > int32_t(ACTION_LAST) ||
7262 actionOverrideX == ACTION_HORIZONTALIZED_SCROLL) {
7263 NS_WARNING("Unsupported action override pref value, didn't override.")NS_DebugBreak(NS_DEBUG_WARNING, "Unsupported action override pref value, didn't override."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7263)
;
7264 actionOverrideX = -1;
7265 }
7266 mOverriddenActionsX[aIndex] = (actionOverrideX == -1)
7267 ? static_cast<Action>(action)
7268 : static_cast<Action>(actionOverrideX);
7269}
7270
7271void EventStateManager::WheelPrefs::GetMultiplierForDeltaXAndY(
7272 const WidgetWheelEvent* aEvent, Index aIndex, double* aMultiplierForDeltaX,
7273 double* aMultiplierForDeltaY) {
7274 *aMultiplierForDeltaX = mMultiplierX[aIndex];
7275 *aMultiplierForDeltaY = mMultiplierY[aIndex];
7276 // If the event has been horizontalized(I.e. treated as a horizontal wheel
7277 // scroll for a vertical wheel scroll), then we should swap mMultiplierX and
7278 // mMultiplierY. By doing this, multipliers will still apply to the delta
7279 // values they origianlly corresponded to.
7280 if (aEvent->mDeltaValuesHorizontalizedForDefaultHandler &&
7281 ComputeActionFor(aEvent) == ACTION_HORIZONTALIZED_SCROLL) {
7282 std::swap(*aMultiplierForDeltaX, *aMultiplierForDeltaY);
7283 }
7284}
7285
7286void EventStateManager::WheelPrefs::ApplyUserPrefsToDelta(
7287 WidgetWheelEvent* aEvent) {
7288 if (aEvent->mCustomizedByUserPrefs) {
7289 return;
7290 }
7291
7292 Index index = GetIndexFor(aEvent);
7293 Init(index);
7294
7295 double multiplierForDeltaX = 1.0, multiplierForDeltaY = 1.0;
7296 GetMultiplierForDeltaXAndY(aEvent, index, &multiplierForDeltaX,
7297 &multiplierForDeltaY);
7298 aEvent->mDeltaX *= multiplierForDeltaX;
7299 aEvent->mDeltaY *= multiplierForDeltaY;
7300 aEvent->mDeltaZ *= mMultiplierZ[index];
7301
7302 // If the multiplier is 1.0 or -1.0, i.e., it doesn't change the absolute
7303 // value, we should use lineOrPageDelta values which were set by widget.
7304 // Otherwise, we need to compute them from accumulated delta values.
7305 if (!NeedToComputeLineOrPageDelta(aEvent)) {
7306 aEvent->mLineOrPageDeltaX *= static_cast<int32_t>(multiplierForDeltaX);
7307 aEvent->mLineOrPageDeltaY *= static_cast<int32_t>(multiplierForDeltaY);
7308 } else {
7309 aEvent->mLineOrPageDeltaX = 0;
7310 aEvent->mLineOrPageDeltaY = 0;
7311 }
7312
7313 aEvent->mCustomizedByUserPrefs =
7314 ((mMultiplierX[index] != 1.0) || (mMultiplierY[index] != 1.0) ||
7315 (mMultiplierZ[index] != 1.0));
7316}
7317
7318void EventStateManager::WheelPrefs::CancelApplyingUserPrefsFromOverflowDelta(
7319 WidgetWheelEvent* aEvent) {
7320 Index index = GetIndexFor(aEvent);
7321 Init(index);
7322
7323 // XXX If the multiplier pref value is negative, the scroll direction was
7324 // changed and caused to scroll different direction. In such case,
7325 // this method reverts the sign of overflowDelta. Does it make widget
7326 // happy? Although, widget can know the pref applied delta values by
7327 // referrencing the deltaX and deltaY of the event.
7328
7329 double multiplierForDeltaX = 1.0, multiplierForDeltaY = 1.0;
7330 GetMultiplierForDeltaXAndY(aEvent, index, &multiplierForDeltaX,
7331 &multiplierForDeltaY);
7332 if (multiplierForDeltaX) {
7333 aEvent->mOverflowDeltaX /= multiplierForDeltaX;
7334 }
7335 if (multiplierForDeltaY) {
7336 aEvent->mOverflowDeltaY /= multiplierForDeltaY;
7337 }
7338}
7339
7340EventStateManager::WheelPrefs::Action
7341EventStateManager::WheelPrefs::ComputeActionFor(
7342 const WidgetWheelEvent* aEvent) {
7343 Index index = GetIndexFor(aEvent);
7344 Init(index);
7345
7346 bool deltaXPreferred = (Abs(aEvent->mDeltaX) > Abs(aEvent->mDeltaY) &&
7347 Abs(aEvent->mDeltaX) > Abs(aEvent->mDeltaZ));
7348 Action* actions = deltaXPreferred ? mOverriddenActionsX : mActions;
7349 if (actions[index] == ACTION_NONE || actions[index] == ACTION_SCROLL ||
7350 actions[index] == ACTION_HORIZONTALIZED_SCROLL) {
7351 return actions[index];
7352 }
7353
7354 // Momentum events shouldn't run special actions.
7355 if (aEvent->mIsMomentum) {
7356 // Use the default action. Note that user might kill the wheel scrolling.
7357 Init(INDEX_DEFAULT);
7358 if (actions[INDEX_DEFAULT] == ACTION_SCROLL ||
7359 actions[INDEX_DEFAULT] == ACTION_HORIZONTALIZED_SCROLL) {
7360 return actions[INDEX_DEFAULT];
7361 }
7362 return ACTION_NONE;
7363 }
7364
7365 return actions[index];
7366}
7367
7368bool EventStateManager::WheelPrefs::NeedToComputeLineOrPageDelta(
7369 const WidgetWheelEvent* aEvent) {
7370 Index index = GetIndexFor(aEvent);
7371 Init(index);
7372
7373 return (mMultiplierX[index] != 1.0 && mMultiplierX[index] != -1.0) ||
7374 (mMultiplierY[index] != 1.0 && mMultiplierY[index] != -1.0);
7375}
7376
7377void EventStateManager::WheelPrefs::GetUserPrefsForEvent(
7378 const WidgetWheelEvent* aEvent, double* aOutMultiplierX,
7379 double* aOutMultiplierY) {
7380 Index index = GetIndexFor(aEvent);
7381 Init(index);
7382
7383 double multiplierForDeltaX = 1.0, multiplierForDeltaY = 1.0;
7384 GetMultiplierForDeltaXAndY(aEvent, index, &multiplierForDeltaX,
7385 &multiplierForDeltaY);
7386 *aOutMultiplierX = multiplierForDeltaX;
7387 *aOutMultiplierY = multiplierForDeltaY;
7388}
7389
7390// static
7391Maybe<layers::APZWheelAction> EventStateManager::APZWheelActionFor(
7392 const WidgetWheelEvent* aEvent) {
7393 if (aEvent->mMessage != eWheel) {
7394 return Nothing();
7395 }
7396 WheelPrefs::Action action =
7397 WheelPrefs::GetInstance()->ComputeActionFor(aEvent);
7398 switch (action) {
7399 case WheelPrefs::ACTION_SCROLL:
7400 case WheelPrefs::ACTION_HORIZONTALIZED_SCROLL:
7401 return Some(layers::APZWheelAction::Scroll);
7402 case WheelPrefs::ACTION_PINCH_ZOOM:
7403 return Some(layers::APZWheelAction::PinchZoom);
7404 default:
7405 return Nothing();
7406 }
7407}
7408
7409// static
7410WheelDeltaAdjustmentStrategy EventStateManager::GetWheelDeltaAdjustmentStrategy(
7411 const WidgetWheelEvent& aEvent) {
7412 if (aEvent.mMessage != eWheel) {
7413 return WheelDeltaAdjustmentStrategy::eNone;
7414 }
7415 switch (WheelPrefs::GetInstance()->ComputeActionFor(&aEvent)) {
7416 case WheelPrefs::ACTION_SCROLL:
7417 if (StaticPrefs::mousewheel_autodir_enabled() && 0 == aEvent.mDeltaZ) {
7418 if (StaticPrefs::mousewheel_autodir_honourroot()) {
7419 return WheelDeltaAdjustmentStrategy::eAutoDirWithRootHonour;
7420 }
7421 return WheelDeltaAdjustmentStrategy::eAutoDir;
7422 }
7423 return WheelDeltaAdjustmentStrategy::eNone;
7424 case WheelPrefs::ACTION_HORIZONTALIZED_SCROLL:
7425 return WheelDeltaAdjustmentStrategy::eHorizontalize;
7426 default:
7427 break;
7428 }
7429 return WheelDeltaAdjustmentStrategy::eNone;
7430}
7431
7432void EventStateManager::GetUserPrefsForWheelEvent(
7433 const WidgetWheelEvent* aEvent, double* aOutMultiplierX,
7434 double* aOutMultiplierY) {
7435 WheelPrefs::GetInstance()->GetUserPrefsForEvent(aEvent, aOutMultiplierX,
7436 aOutMultiplierY);
7437}
7438
7439bool EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedX(
7440 const WidgetWheelEvent* aEvent) {
7441 Index index = GetIndexFor(aEvent);
7442 Init(index);
7443 return Abs(mMultiplierX[index]) >=
7444 MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
7445}
7446
7447bool EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedY(
7448 const WidgetWheelEvent* aEvent) {
7449 Index index = GetIndexFor(aEvent);
7450 Init(index);
7451 return Abs(mMultiplierY[index]) >=
7452 MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
7453}
7454
7455} // namespace mozilla