Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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