Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsCOMPtr.h
Warning:line 342, column 5
Branch condition evaluates to a garbage value

Annotated Source Code

Press '?' to see keyboard shortcuts

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

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

1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#include "EventStateManager.h"
8
9#include "mozilla/AsyncEventDispatcher.h"
10#include "mozilla/Attributes.h"
11#include "mozilla/EditorBase.h"
12#include "mozilla/EventDispatcher.h"
13#include "mozilla/EventForwards.h"
14#include "mozilla/Hal.h"
15#include "mozilla/HTMLEditor.h"
16#include "mozilla/IMEStateManager.h"
17#include "mozilla/Likely.h"
18#include "mozilla/FocusModel.h"
19#include "mozilla/MiscEvents.h"
20#include "mozilla/MathAlgorithms.h"
21#include "mozilla/MouseEvents.h"
22#include "mozilla/PointerLockManager.h"
23#include "mozilla/PresShell.h"
24#include "mozilla/ScopeExit.h"
25#include "mozilla/ScrollTypes.h"
26#include "mozilla/TextComposition.h"
27#include "mozilla/TextControlElement.h"
28#include "mozilla/TextEditor.h"
29#include "mozilla/TextEvents.h"
30#include "mozilla/TouchEvents.h"
31#include "mozilla/Telemetry.h"
32#include "mozilla/UniquePtr.h"
33#include "mozilla/dom/BrowserBridgeChild.h"
34#include "mozilla/dom/BrowsingContext.h"
35#include "mozilla/dom/CanonicalBrowsingContext.h"
36#include "mozilla/dom/ContentChild.h"
37#include "mozilla/dom/DOMIntersectionObserver.h"
38#include "mozilla/dom/DragEvent.h"
39#include "mozilla/dom/Event.h"
40#include "mozilla/dom/FrameLoaderBinding.h"
41#include "mozilla/dom/HTMLLabelElement.h"
42#include "mozilla/dom/HTMLInputElement.h"
43#include "mozilla/dom/MouseEventBinding.h"
44#include "mozilla/dom/BrowserChild.h"
45#include "mozilla/dom/PointerEventHandler.h"
46#include "mozilla/dom/UIEvent.h"
47#include "mozilla/dom/UIEventBinding.h"
48#include "mozilla/dom/UserActivation.h"
49#include "mozilla/dom/WheelEventBinding.h"
50#include "mozilla/glean/GleanMetrics.h"
51#include "mozilla/ScrollContainerFrame.h"
52#include "mozilla/StaticPrefs_accessibility.h"
53#include "mozilla/StaticPrefs_browser.h"
54#include "mozilla/StaticPrefs_dom.h"
55#include "mozilla/StaticPrefs_layout.h"
56#include "mozilla/StaticPrefs_mousewheel.h"
57#include "mozilla/StaticPrefs_ui.h"
58#include "mozilla/StaticPrefs_zoom.h"
59
60#include "ContentEventHandler.h"
61#include "IMEContentObserver.h"
62#include "WheelHandlingHelper.h"
63#include "RemoteDragStartData.h"
64
65#include "nsCommandParams.h"
66#include "nsCOMPtr.h"
67#include "nsCopySupport.h"
68#include "nsFocusManager.h"
69#include "nsGenericHTMLElement.h"
70#include "nsIClipboard.h"
71#include "nsIContent.h"
72#include "nsIContentInlines.h"
73#include "mozilla/dom/Document.h"
74#include "nsICookieJarSettings.h"
75#include "nsIFrame.h"
76#include "nsFrameLoaderOwner.h"
77#include "nsIWeakReferenceUtils.h"
78#include "nsIWidget.h"
79#include "nsLiteralString.h"
80#include "nsPresContext.h"
81#include "nsTArray.h"
82#include "nsGkAtoms.h"
83#include "nsIFormControl.h"
84#include "nsComboboxControlFrame.h"
85#include "nsIDOMXULControlElement.h"
86#include "nsNameSpaceManager.h"
87#include "nsIBaseWindow.h"
88#include "nsFrameSelection.h"
89#include "nsPIDOMWindow.h"
90#include "nsPIWindowRoot.h"
91#include "nsIWebNavigation.h"
92#include "nsIDocumentViewer.h"
93#include "nsFrameManager.h"
94#include "nsIBrowserChild.h"
95#include "nsMenuPopupFrame.h"
96
97#include "nsIObserverService.h"
98#include "nsIDocShell.h"
99
100#include "nsSubDocumentFrame.h"
101#include "nsLayoutUtils.h"
102#include "nsIInterfaceRequestorUtils.h"
103#include "nsUnicharUtils.h"
104#include "nsContentUtils.h"
105
106#include "imgIContainer.h"
107#include "nsIProperties.h"
108#include "nsISupportsPrimitives.h"
109
110#include "nsServiceManagerUtils.h"
111#include "nsITimer.h"
112#include "nsFontMetrics.h"
113#include "nsIDragService.h"
114#include "nsIDragSession.h"
115#include "mozilla/dom/DataTransfer.h"
116#include "nsContentAreaDragDrop.h"
117#include "nsTreeBodyFrame.h"
118#include "nsIController.h"
119#include "mozilla/Services.h"
120#include "mozilla/dom/ContentParent.h"
121#include "mozilla/dom/Record.h"
122#include "mozilla/dom/Selection.h"
123
124#include "mozilla/Preferences.h"
125#include "mozilla/LookAndFeel.h"
126#include "mozilla/ProfilerLabels.h"
127#include "Units.h"
128
129#ifdef XP_MACOSX
130# import <ApplicationServices/ApplicationServices.h>
131#endif
132
133namespace mozilla {
134
135using namespace dom;
136
137static const LayoutDeviceIntPoint kInvalidRefPoint =
138 LayoutDeviceIntPoint(-1, -1);
139
140static uint32_t gMouseOrKeyboardEventCounter = 0;
141static nsITimer* gUserInteractionTimer = nullptr;
142static nsITimerCallback* gUserInteractionTimerCallback = nullptr;
143
144static const double kCursorLoadingTimeout = 1000; // ms
145static AutoWeakFrame gLastCursorSourceFrame;
146static TimeStamp gLastCursorUpdateTime;
147static TimeStamp gTypingStartTime;
148static TimeStamp gTypingEndTime;
149static int32_t gTypingInteractionKeyPresses = 0;
150static dom::InteractionData gTypingInteraction = {};
151
152static inline int32_t RoundDown(double aDouble) {
153 return (aDouble > 0) ? static_cast<int32_t>(floor(aDouble))
154 : static_cast<int32_t>(ceil(aDouble));
155}
156
157static bool IsSelectingLink(nsIFrame* aTargetFrame) {
158 if (!aTargetFrame) {
159 return false;
160 }
161 const nsFrameSelection* frameSel = aTargetFrame->GetConstFrameSelection();
162 if (!frameSel || !frameSel->GetDragState()) {
163 return false;
164 }
165
166 if (!nsContentUtils::GetClosestLinkInFlatTree(aTargetFrame->GetContent())) {
167 return false;
168 }
169 return true;
170}
171
172static UniquePtr<WidgetMouseEvent> CreateMouseOrPointerWidgetEvent(
173 WidgetMouseEvent* aMouseEvent, EventMessage aMessage,
174 EventTarget* aRelatedTarget);
175
176/**
177 * Returns the common ancestor for mouseup purpose, given the
178 * current mouseup target and the previous mousedown target.
179 */
180static nsINode* GetCommonAncestorForMouseUp(
181 nsINode* aCurrentMouseUpTarget, nsINode* aLastMouseDownTarget,
182 Maybe<FormControlType>& aLastMouseDownInputControlType) {
183 if (!aCurrentMouseUpTarget || !aLastMouseDownTarget) {
184 return nullptr;
185 }
186
187 if (aCurrentMouseUpTarget == aLastMouseDownTarget) {
188 return aCurrentMouseUpTarget;
189 }
190
191 // Build the chain of parents
192 AutoTArray<nsINode*, 30> parents1;
193 do {
194 parents1.AppendElement(aCurrentMouseUpTarget);
195 aCurrentMouseUpTarget = aCurrentMouseUpTarget->GetFlattenedTreeParentNode();
196 } while (aCurrentMouseUpTarget);
197
198 AutoTArray<nsINode*, 30> parents2;
199 do {
200 parents2.AppendElement(aLastMouseDownTarget);
201 if (aLastMouseDownTarget == parents1.LastElement()) {
202 break;
203 }
204 aLastMouseDownTarget = aLastMouseDownTarget->GetFlattenedTreeParentNode();
205 } while (aLastMouseDownTarget);
206
207 // Find where the parent chain differs
208 uint32_t pos1 = parents1.Length();
209 uint32_t pos2 = parents2.Length();
210 nsINode* parent = nullptr;
211 for (uint32_t len = std::min(pos1, pos2); len > 0; --len) {
212 nsINode* child1 = parents1.ElementAt(--pos1);
213 nsINode* child2 = parents2.ElementAt(--pos2);
214 if (child1 != child2) {
215 break;
216 }
217
218 // If the input control type is different between mouseup and mousedown,
219 // this is not a valid click.
220 if (HTMLInputElement* input = HTMLInputElement::FromNodeOrNull(child1)) {
221 if (aLastMouseDownInputControlType.isSome() &&
222 aLastMouseDownInputControlType.ref() != input->ControlType()) {
223 break;
224 }
225 }
226 parent = child1;
227 }
228
229 return parent;
230}
231
232LazyLogModule sMouseBoundaryLog("MouseBoundaryEvents");
233LazyLogModule sPointerBoundaryLog("PointerBoundaryEvents");
234
235/******************************************************************/
236/* mozilla::UITimerCallback */
237/******************************************************************/
238
239class UITimerCallback final : public nsITimerCallback, public nsINamed {
240 public:
241 UITimerCallback() : mPreviousCount(0) {}
242 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
243 NS_DECL_NSITIMERCALLBACKvirtual nsresult Notify(nsITimer *timer) override; inline void
_ensure_GetName_exists(void) { static_assert(std::is_convertible
<decltype(this), nsINamed*>::value, "nsITimerCallback implementations must also implement nsINamed"
); }
244 NS_DECL_NSINAMEDvirtual nsresult GetName(nsACString& aName) override;
245 private:
246 ~UITimerCallback() = default;
247 uint32_t mPreviousCount;
248};
249
250NS_IMPL_ISUPPORTS(UITimerCallback, nsITimerCallback, nsINamed)MozExternalRefCountType UITimerCallback::AddRef(void) { static_assert
(!std::is_destructible_v<UITimerCallback>, "Reference-counted class "
"UITimerCallback" " should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
250; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("UITimerCallback" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("UITimerCallback" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"UITimerCallback\" != nullptr" " (" "Must specify a name" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"UITimerCallback\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 250; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("UITimerCallback" " not thread-safe"); nsrefcnt
count = ++mRefCnt; NS_LogAddRef((this), (count), ("UITimerCallback"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
UITimerCallback::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 250
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("UITimerCallback" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("UITimerCallback" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"UITimerCallback\" != nullptr" " (" "Must specify a name" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"UITimerCallback\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 250; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("UITimerCallback" " not thread-safe"); const
char* const nametmp = "UITimerCallback"; nsrefcnt count = --
mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count
== 0) { mRefCnt = 1; delete (this); return 0; } return count
; } nsresult UITimerCallback::QueryInterface(const nsIID&
aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<UITimerCallback, nsITimerCallback>, int32_t
( reinterpret_cast<char*>(static_cast<nsITimerCallback
*>((UITimerCallback*)0x1000)) - reinterpret_cast<char*>
((UITimerCallback*)0x1000))}, {&mozilla::detail::kImplementedIID
<UITimerCallback, nsINamed>, int32_t( reinterpret_cast<
char*>(static_cast<nsINamed*>((UITimerCallback*)0x1000
)) - reinterpret_cast<char*>((UITimerCallback*)0x1000))
}, {&mozilla::detail::kImplementedIID<UITimerCallback,
nsISupports>, int32_t(reinterpret_cast<char*>(static_cast
<nsISupports*>( static_cast<nsITimerCallback*>((UITimerCallback
*)0x1000))) - reinterpret_cast<char*>((UITimerCallback*
)0x1000))}, { nullptr, 0 } } ; static_assert((sizeof(table) /
sizeof(table[0])) > 1, "need at least 1 interface"); rv =
NS_TableDrivenQI(static_cast<void*>(this), aIID, aInstancePtr
, table); return rv; }
251
252// If aTimer is nullptr, this method always sends "user-interaction-inactive"
253// notification.
254NS_IMETHODIMPnsresult
255UITimerCallback::Notify(nsITimer* aTimer) {
256 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
257 if (!obs) return NS_ERROR_FAILURE;
258 if ((gMouseOrKeyboardEventCounter == mPreviousCount) || !aTimer) {
259 gMouseOrKeyboardEventCounter = 0;
260 obs->NotifyObservers(nullptr, "user-interaction-inactive", nullptr);
261 if (gUserInteractionTimer) {
262 gUserInteractionTimer->Cancel();
263 NS_RELEASE(gUserInteractionTimer)do { (gUserInteractionTimer)->Release(); (gUserInteractionTimer
) = 0; } while (0)
;
264 }
265 } else {
266 obs->NotifyObservers(nullptr, "user-interaction-active", nullptr);
267 EventStateManager::UpdateUserActivityTimer();
268
269 if (XRE_IsParentProcess()) {
270 hal::BatteryInformation batteryInfo;
271 hal::GetCurrentBatteryInformation(&batteryInfo);
272 glean::power_battery::percentage_when_user_active.AccumulateSingleSample(
273 uint64_t(batteryInfo.level() * 100));
274 }
275 }
276 mPreviousCount = gMouseOrKeyboardEventCounter;
277 return NS_OK;
278}
279
280NS_IMETHODIMPnsresult
281UITimerCallback::GetName(nsACString& aName) {
282 aName.AssignLiteral("UITimerCallback_timer");
283 return NS_OK;
284}
285
286/******************************************************************/
287/* mozilla::OverOutElementsWrapper */
288/******************************************************************/
289
290NS_IMPL_CYCLE_COLLECTION(OverOutElementsWrapper, mDeepestEnterEventTarget,OverOutElementsWrapper::cycleCollection OverOutElementsWrapper
::_cycleCollectorGlobal; void OverOutElementsWrapper::cycleCollection
::Unlink(void* p) { OverOutElementsWrapper* tmp = DowncastCCParticipant
<OverOutElementsWrapper>(p); ImplCycleCollectionUnlink(
tmp->mDeepestEnterEventTarget); ImplCycleCollectionUnlink(
tmp->mDispatchingOverEventTarget); ImplCycleCollectionUnlink
(tmp->mDispatchingOutOrDeepestLeaveEventTarget); (void)tmp
; } nsresult OverOutElementsWrapper::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { OverOutElementsWrapper
* tmp = DowncastCCParticipant<OverOutElementsWrapper>(p
); cb.DescribeRefCountedNode(tmp->mRefCnt.get(), "OverOutElementsWrapper"
); ImplCycleCollectionTraverse(cb, tmp->mDeepestEnterEventTarget
, "mDeepestEnterEventTarget", 0); ImplCycleCollectionTraverse
(cb, tmp->mDispatchingOverEventTarget, "mDispatchingOverEventTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDispatchingOutOrDeepestLeaveEventTarget
, "mDispatchingOutOrDeepestLeaveEventTarget", 0); (void)tmp; return
NS_OK; }
291 mDispatchingOverEventTarget,OverOutElementsWrapper::cycleCollection OverOutElementsWrapper
::_cycleCollectorGlobal; void OverOutElementsWrapper::cycleCollection
::Unlink(void* p) { OverOutElementsWrapper* tmp = DowncastCCParticipant
<OverOutElementsWrapper>(p); ImplCycleCollectionUnlink(
tmp->mDeepestEnterEventTarget); ImplCycleCollectionUnlink(
tmp->mDispatchingOverEventTarget); ImplCycleCollectionUnlink
(tmp->mDispatchingOutOrDeepestLeaveEventTarget); (void)tmp
; } nsresult OverOutElementsWrapper::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { OverOutElementsWrapper
* tmp = DowncastCCParticipant<OverOutElementsWrapper>(p
); cb.DescribeRefCountedNode(tmp->mRefCnt.get(), "OverOutElementsWrapper"
); ImplCycleCollectionTraverse(cb, tmp->mDeepestEnterEventTarget
, "mDeepestEnterEventTarget", 0); ImplCycleCollectionTraverse
(cb, tmp->mDispatchingOverEventTarget, "mDispatchingOverEventTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDispatchingOutOrDeepestLeaveEventTarget
, "mDispatchingOutOrDeepestLeaveEventTarget", 0); (void)tmp; return
NS_OK; }
292 mDispatchingOutOrDeepestLeaveEventTarget)OverOutElementsWrapper::cycleCollection OverOutElementsWrapper
::_cycleCollectorGlobal; void OverOutElementsWrapper::cycleCollection
::Unlink(void* p) { OverOutElementsWrapper* tmp = DowncastCCParticipant
<OverOutElementsWrapper>(p); ImplCycleCollectionUnlink(
tmp->mDeepestEnterEventTarget); ImplCycleCollectionUnlink(
tmp->mDispatchingOverEventTarget); ImplCycleCollectionUnlink
(tmp->mDispatchingOutOrDeepestLeaveEventTarget); (void)tmp
; } nsresult OverOutElementsWrapper::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { OverOutElementsWrapper
* tmp = DowncastCCParticipant<OverOutElementsWrapper>(p
); cb.DescribeRefCountedNode(tmp->mRefCnt.get(), "OverOutElementsWrapper"
); ImplCycleCollectionTraverse(cb, tmp->mDeepestEnterEventTarget
, "mDeepestEnterEventTarget", 0); ImplCycleCollectionTraverse
(cb, tmp->mDispatchingOverEventTarget, "mDispatchingOverEventTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDispatchingOutOrDeepestLeaveEventTarget
, "mDispatchingOutOrDeepestLeaveEventTarget", 0); (void)tmp; return
NS_OK; }
293NS_IMPL_CYCLE_COLLECTING_ADDREF(OverOutElementsWrapper)MozExternalRefCountType OverOutElementsWrapper::AddRef(void) {
static_assert(!std::is_destructible_v<OverOutElementsWrapper
>, "Reference-counted class " "OverOutElementsWrapper" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 293); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
293; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); _mOwningThread.AssertOwnership("OverOutElementsWrapper"
" not thread-safe"); nsISupports* base = OverOutElementsWrapper
::cycleCollection::Upcast(this); nsrefcnt count = mRefCnt.incr
(base); NS_LogAddRef((this), (count), ("OverOutElementsWrapper"
), (uint32_t)(sizeof(*this))); return count; }
294NS_IMPL_CYCLE_COLLECTING_RELEASE(OverOutElementsWrapper)MozExternalRefCountType OverOutElementsWrapper::Release(void)
{ do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 294); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 294
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); _mOwningThread.AssertOwnership("OverOutElementsWrapper"
" not thread-safe"); nsISupports* base = OverOutElementsWrapper
::cycleCollection::Upcast(this); nsrefcnt count = mRefCnt.decr
(base); NS_LogRelease((this), (count), ("OverOutElementsWrapper"
)); return count; } void OverOutElementsWrapper::DeleteCycleCollectable
(void) { delete (this); }
295
296NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(OverOutElementsWrapper)nsresult OverOutElementsWrapper::QueryInterface(const nsIID&
aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 296); MOZ_PretendNoReturn(); } } while (0); nsISupports* foundInterface
; if (TopThreeWordsEquals( aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID), (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID)) && (LowWordEquals(aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID)) || LowWordEquals(aIID, (nsCycleCollectionISupports::COMTypeInfo
<nsCycleCollectionISupports, void>::kIID)))) { if (LowWordEquals
(aIID, (nsXPCOMCycleCollectionParticipant::COMTypeInfo<nsXPCOMCycleCollectionParticipant
, void>::kIID))) { *aInstancePtr = OverOutElementsWrapper::
cycleCollection::GetParticipant(); return NS_OK; } if (LowWordEquals
(aIID, (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID))) { *aInstancePtr = OverOutElementsWrapper::
cycleCollection::Upcast(this); return NS_OK; } foundInterface
= nullptr; } else
297 NS_INTERFACE_MAP_ENTRY(nsISupports)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupports>)) foundInterface = static_cast
<nsISupports*>(this); else
298NS_INTERFACE_MAP_ENDfoundInterface = 0; nsresult status; if (!foundInterface) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(!aIID.Equals((nsISupports::COMTypeInfo<nsISupports
, void>::kIID)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aIID.Equals((nsISupports::COMTypeInfo
<nsISupports, void>::kIID))))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 298); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
")"); do { *((volatile int*)__null) = 298; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); status = NS_NOINTERFACE
; } else { (foundInterface)->AddRef(); status = NS_OK; } *
aInstancePtr = foundInterface; return status; }
299
300already_AddRefed<nsIWidget> OverOutElementsWrapper::GetLastOverWidget() const {
301 nsCOMPtr<nsIWidget> widget = do_QueryReferent(mLastOverWidget);
302 return widget.forget();
303}
304
305void OverOutElementsWrapper::ContentRemoved(nsIContent& aContent) {
306 if (!mDeepestEnterEventTarget) {
307 return;
308 }
309
310 if (!nsContentUtils::ContentIsFlattenedTreeDescendantOf(
311 mDeepestEnterEventTarget, &aContent)) {
312 return;
313 }
314
315 LogModule* const logModule = mType == BoundaryEventType::Mouse
316 ? sMouseBoundaryLog
317 : sPointerBoundaryLog;
318
319 if (!StaticPrefs::
320 dom_events_mouse_pointer_boundary_keep_enter_targets_after_over_target_removed()) {
321 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"over\" event target (%p) is removed"
, mDeepestEnterEventTarget.get()); } } while (0)
322 ("The last \"over\" event target (%p) is removed",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"over\" event target (%p) is removed"
, mDeepestEnterEventTarget.get()); } } while (0)
323 mDeepestEnterEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"over\" event target (%p) is removed"
, mDeepestEnterEventTarget.get()); } } while (0)
;
324 StoreOverEventTargetAndDeepestEnterEventTarget(nullptr);
325 return;
326 }
327
328 if (mDispatchingOverEventTarget &&
329 (mDeepestEnterEventTarget == mDispatchingOverEventTarget ||
330 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
331 mDispatchingOverEventTarget, &aContent))) {
332 if (mDispatchingOverEventTarget ==
333 mDispatchingOutOrDeepestLeaveEventTarget) {
334 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
335 ("The dispatching \"%s\" event target (%p) is removed",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
336 LastOverEventTargetIsOutEventTarget() ? "out" : "leave",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
337 mDispatchingOutOrDeepestLeaveEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
;
338 mDispatchingOutOrDeepestLeaveEventTarget = nullptr;
339 }
340 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"over\" event target (%p) is removed"
, mDispatchingOverEventTarget.get()); } } while (0)
341 ("The dispatching \"over\" event target (%p) is removed",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"over\" event target (%p) is removed"
, mDispatchingOverEventTarget.get()); } } while (0)
342 mDispatchingOverEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"over\" event target (%p) is removed"
, mDispatchingOverEventTarget.get()); } } while (0)
;
343 mDispatchingOverEventTarget = nullptr;
344 }
345 if (mDispatchingOutOrDeepestLeaveEventTarget &&
346 (mDeepestEnterEventTarget == mDispatchingOutOrDeepestLeaveEventTarget ||
347 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
348 mDispatchingOutOrDeepestLeaveEventTarget, &aContent))) {
349 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
350 ("The dispatching \"%s\" event target (%p) is removed",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
351 LastOverEventTargetIsOutEventTarget() ? "out" : "leave",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
352 mDispatchingOutOrDeepestLeaveEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
;
353 mDispatchingOutOrDeepestLeaveEventTarget = nullptr;
354 }
355 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
356 ("The last \"%s\" event target (%p) is removed and now the last "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
357 "deepest enter target becomes %s(%p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
358 LastOverEventTargetIsOutEventTarget() ? "over" : "enter",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
359 mDeepestEnterEventTarget.get(),do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
360 aContent.GetFlattenedTreeParent()do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
361 ? ToString(*aContent.GetFlattenedTreeParent()).c_str()do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
362 : "nullptr",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
363 aContent.GetFlattenedTreeParent()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
;
364 UpdateDeepestEnterEventTarget(aContent.GetFlattenedTreeParent());
365}
366
367void OverOutElementsWrapper::TryToRestorePendingRemovedOverTarget(
368 const WidgetEvent* aEvent) {
369 if (!MaybeHasPendingRemovingOverEventTarget()) {
370 return;
371 }
372
373 LogModule* const logModule = mType == BoundaryEventType::Mouse
374 ? sMouseBoundaryLog
375 : sPointerBoundaryLog;
376
377 // If we receive a mouse event immediately, let's try to restore the last
378 // "over" event target as the following "out" event target. We assume that a
379 // synthesized mousemove or another mouse event is being dispatched at latest
380 // the next animation frame from the removal. However, synthesized mouse move
381 // which is enqueued by ContentRemoved() may not sent to this instance because
382 // the target is considered with the latest layout, so the document of this
383 // instance may be moved somewhere before the next animation frame.
384 // Therefore, we should not restore the last "over" target if we receive an
385 // unexpected event like a keyboard event, a wheel event, etc.
386 if (aEvent->AsMouseEvent()) {
387 // Restore the original "over" event target should be allowed only when it's
388 // reconnected under the last deepest "enter" event target because we need
389 // to dispatch "leave" events later at least on the ancestors which have
390 // never been removed from the tree.
391 // XXX If new ancestor is inserted between mDeepestEnterEventTarget and
392 // mPendingToRemoveLastOverEventTarget, we will dispatch "leave" event even
393 // though we have not dispatched "enter" event on the element. For fixing
394 // this, we need to store the full path of the last "out" event target when
395 // it's removed from the tree. I guess we can be relax for this issue
396 // because this hack is required for web apps which reconnect the target
397 // to the same position immediately.
398 // XXX Should be IsInclusiveFlatTreeDescendantOf()? However, it may
399 // be reconnected into a subtree which is different from where the
400 // last over element was.
401 nsCOMPtr<nsIContent> pendingRemovingOverEventTarget =
402 GetPendingRemovingOverEventTarget();
403 if (pendingRemovingOverEventTarget &&
404 pendingRemovingOverEventTarget->IsInclusiveDescendantOf(
405 mDeepestEnterEventTarget)) {
406 // StoreOverEventTargetAndDeepestEnterEventTarget() always resets
407 // mLastOverWidget. When we restore the pending removing "over" event
408 // target, we need to keep storing the original "over" widget too.
409 nsCOMPtr<nsIWeakReference> widget = std::move(mLastOverWidget);
410 StoreOverEventTargetAndDeepestEnterEventTarget(
411 pendingRemovingOverEventTarget);
412 mLastOverWidget = std::move(widget);
413 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
414 ("The \"over\" event target (%p) is restored",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
415 mDeepestEnterEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
;
416 return;
417 }
418 MOZ_LOG(logModule, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
419 ("Forgetting the last \"over\" event target (%p) because it is not "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
420 "reconnected under the deepest enter event target (%p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
421 mPendingRemovingOverEventTarget.get(),do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
422 mDeepestEnterEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
;
423 } else {
424 MOZ_LOG(logModule, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
425 ("Forgetting the last \"over\" event target (%p) because an "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
426 "unexpected event (%s) is being dispatched, that means that "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
427 "EventStateManager didn't receive a synthesized mousemove which "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
428 "should be dispatched at next animation frame from the removal",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
429 mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage)))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
;
430 }
431
432 // Now, we should not restore mPendingRemovingOverEventTarget to
433 // mDeepestEnterEventTarget anymore since mPendingRemovingOverEventTarget was
434 // moved outside the subtree of mDeepestEnterEventTarget.
435 mPendingRemovingOverEventTarget = nullptr;
436}
437
438void OverOutElementsWrapper::WillDispatchOverAndEnterEvent(
439 nsIContent* aOverEventTarget) {
440 StoreOverEventTargetAndDeepestEnterEventTarget(aOverEventTarget);
441 // Store the first "over" event target we fire and don't refire "over" event
442 // to that element while the first "over" event is still ongoing.
443 mDispatchingOverEventTarget = aOverEventTarget;
444}
445
446void OverOutElementsWrapper::DidDispatchOverAndEnterEvent(
447 nsIContent* aOriginalOverTargetInComposedDoc,
448 nsIWidget* aOverEventTargetWidget) {
449 mDispatchingOverEventTarget = nullptr;
450 mLastOverWidget = do_GetWeakReference(aOverEventTargetWidget);
451
452 // Pointer Events define that once the `pointerover` event target is removed
453 // from the tree, `pointerout` should not be fired on that and the closest
454 // connected ancestor at the target removal should be kept as the deepest
455 // `pointerleave` target. Therefore, we don't need the special handling for
456 // `pointerout` event target if the last `pointerover` target is temporarily
457 // removed from the tree.
458 if (mType == OverOutElementsWrapper::BoundaryEventType::Pointer) {
459 return;
460 }
461
462 // Assume that the caller checks whether aOriginalOverTarget is in the
463 // original document. If we don't enable the strict mouse/pointer event
464 // boundary event dispatching by the pref (see below),
465 // mDeepestEnterEventTarget is set to nullptr when the last "over" target is
466 // removed. Therefore, we cannot check whether aOriginalOverTarget is in the
467 // original document here.
468 if (!aOriginalOverTargetInComposedDoc) {
469 return;
470 }
471 MOZ_ASSERT_IF(mDeepestEnterEventTarget,do { if (mDeepestEnterEventTarget) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mDeepestEnterEventTarget
->GetComposedDoc() == aOriginalOverTargetInComposedDoc->
GetComposedDoc())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget->
GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
")"); do { *((volatile int*)__null) = 473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
472 mDeepestEnterEventTarget->GetComposedDoc() ==do { if (mDeepestEnterEventTarget) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mDeepestEnterEventTarget
->GetComposedDoc() == aOriginalOverTargetInComposedDoc->
GetComposedDoc())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget->
GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
")"); do { *((volatile int*)__null) = 473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
473 aOriginalOverTargetInComposedDoc->GetComposedDoc())do { if (mDeepestEnterEventTarget) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mDeepestEnterEventTarget
->GetComposedDoc() == aOriginalOverTargetInComposedDoc->
GetComposedDoc())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget->
GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
")"); do { *((volatile int*)__null) = 473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
474 // If the "mouseover" event target is removed temporarily while we're
475 // dispatching "mouseover" and "mouseenter" events and the target gets back
476 // under the deepest enter event target, we should restore the "mouseover"
477 // target.
478 if ((!StaticPrefs::
479 dom_events_mouse_pointer_boundary_keep_enter_targets_after_over_target_removed() &&
480 !mDeepestEnterEventTarget) ||
481 (!LastOverEventTargetIsOutEventTarget() && mDeepestEnterEventTarget &&
482 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
483 aOriginalOverTargetInComposedDoc, mDeepestEnterEventTarget))) {
484 StoreOverEventTargetAndDeepestEnterEventTarget(
485 aOriginalOverTargetInComposedDoc);
486 LogModule* const logModule = mType == BoundaryEventType::Mouse
487 ? sMouseBoundaryLog
488 : sPointerBoundaryLog;
489 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
490 ("The \"over\" event target (%p) is restored",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
491 mDeepestEnterEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
;
492 }
493}
494
495void OverOutElementsWrapper::StoreOverEventTargetAndDeepestEnterEventTarget(
496 nsIContent* aOverEventTargetAndDeepestEnterEventTarget) {
497 mDeepestEnterEventTarget = aOverEventTargetAndDeepestEnterEventTarget;
498 mPendingRemovingOverEventTarget = nullptr;
499 mDeepestEnterEventTargetIsOverEventTarget = !!mDeepestEnterEventTarget;
500 mLastOverWidget = nullptr; // Set it after dispatching the "over" event.
501}
502
503void OverOutElementsWrapper::UpdateDeepestEnterEventTarget(
504 nsIContent* aDeepestEnterEventTarget) {
505 if (MOZ_UNLIKELY(mDeepestEnterEventTarget == aDeepestEnterEventTarget)(__builtin_expect(!!(mDeepestEnterEventTarget == aDeepestEnterEventTarget
), 0))
) {
506 return;
507 }
508
509 if (!aDeepestEnterEventTarget) {
510 // If the root element is removed, we don't need to dispatch "leave"
511 // events on any elements. Therefore, we can forget everything.
512 StoreOverEventTargetAndDeepestEnterEventTarget(nullptr);
513 return;
514 }
515
516 if (LastOverEventTargetIsOutEventTarget()) {
517 MOZ_ASSERT(mDeepestEnterEventTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDeepestEnterEventTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("mDeepestEnterEventTarget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 517); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget"
")"); do { *((volatile int*)__null) = 517; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
518 if (mType == BoundaryEventType::Pointer) {
519 // The spec of Pointer Events defines that once the `pointerover` event
520 // target is removed from the tree, `pointerout` should not be fired on
521 // that and the closest connected ancestor at the target removal should be
522 // kept as the deepest `pointerleave` target. All browsers considers the
523 // last `pointerover` event target is removed immediately when it occurs.
524 // Therefore, we don't need the special handling which we do for the
525 // `mouseout` event target below for considering whether we'll dispatch
526 // `pointerout` on the last `pointerover` target.
527 mPendingRemovingOverEventTarget = nullptr;
528 } else {
529 // Now, the `mouseout` event target is removed from the DOM at least
530 // temporarily. Let's keep storing it for restoring it if it's
531 // reconnected into mDeepestEnterEventTarget in a tick because the other
532 // browsers do not treat temporary removal of the last `mouseover` target
533 // keeps storing it as the next `mouseout` event target.
534 MOZ_ASSERT(!mPendingRemovingOverEventTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mPendingRemovingOverEventTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mPendingRemovingOverEventTarget
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!mPendingRemovingOverEventTarget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 534); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mPendingRemovingOverEventTarget"
")"); do { *((volatile int*)__null) = 534; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
535 MOZ_ASSERT(mDeepestEnterEventTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDeepestEnterEventTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("mDeepestEnterEventTarget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 535); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget"
")"); do { *((volatile int*)__null) = 535; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
536 mPendingRemovingOverEventTarget =
537 do_GetWeakReference(mDeepestEnterEventTarget);
538 }
539 } else {
540 MOZ_ASSERT(!mDeepestEnterEventTargetIsOverEventTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDeepestEnterEventTargetIsOverEventTarget)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!mDeepestEnterEventTargetIsOverEventTarget))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!mDeepestEnterEventTargetIsOverEventTarget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 540); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDeepestEnterEventTargetIsOverEventTarget"
")"); do { *((volatile int*)__null) = 540; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
541 // If mDeepestEnterEventTarget is not the last "over" event target, we've
542 // already done the complicated state managing above. Therefore, we only
543 // need to update mDeepestEnterEventTarget in this case.
544 }
545 mDeepestEnterEventTarget = aDeepestEnterEventTarget;
546 mDeepestEnterEventTargetIsOverEventTarget = false;
547 // Do not update mLastOverWidget here because it's required to ignore some
548 // following pointer events which are fired on widget under different top
549 // level widget.
550}
551
552/******************************************************************/
553/* mozilla::EventStateManager */
554/******************************************************************/
555
556static uint32_t sESMInstanceCount = 0;
557
558bool EventStateManager::sNormalLMouseEventInProcess = false;
559int16_t EventStateManager::sCurrentMouseBtn = MouseButton::eNotPressed;
560EventStateManager* EventStateManager::sActiveESM = nullptr;
561EventStateManager* EventStateManager::sCursorSettingManager = nullptr;
562AutoWeakFrame EventStateManager::sLastDragOverFrame = nullptr;
563LayoutDeviceIntPoint EventStateManager::sPreLockScreenPoint =
564 LayoutDeviceIntPoint(0, 0);
565LayoutDeviceIntPoint EventStateManager::sLastRefPoint = kInvalidRefPoint;
566CSSIntPoint EventStateManager::sLastScreenPoint = CSSIntPoint(0, 0);
567LayoutDeviceIntPoint EventStateManager::sSynthCenteringPoint = kInvalidRefPoint;
568CSSIntPoint EventStateManager::sLastClientPoint = CSSIntPoint(0, 0);
569nsCOMPtr<nsIContent> EventStateManager::sDragOverContent = nullptr;
570
571EventStateManager::WheelPrefs* EventStateManager::WheelPrefs::sInstance =
572 nullptr;
573EventStateManager::DeltaAccumulator*
574 EventStateManager::DeltaAccumulator::sInstance = nullptr;
575
576constexpr const StyleCursorKind kInvalidCursorKind =
577 static_cast<StyleCursorKind>(255);
578
579EventStateManager::EventStateManager()
580 : mLockCursor(kInvalidCursorKind),
581 mCurrentTarget(nullptr),
582 // init d&d gesture state machine variables
583 mGestureDownPoint(0, 0),
584 mGestureModifiers(0),
585 mGestureDownButtons(0),
586 mGestureDownButton(0),
587 mPresContext(nullptr),
588 mShouldAlwaysUseLineDeltas(false),
589 mShouldAlwaysUseLineDeltasInitialized(false),
590 mGestureDownInTextControl(false),
591 mInTouchDrag(false),
592 m_haveShutdown(false) {
593 if (sESMInstanceCount == 0) {
594 gUserInteractionTimerCallback = new UITimerCallback();
595 if (gUserInteractionTimerCallback) NS_ADDREF(gUserInteractionTimerCallback)(gUserInteractionTimerCallback)->AddRef();
596 UpdateUserActivityTimer();
597 }
598 ++sESMInstanceCount;
599}
600
601nsresult EventStateManager::UpdateUserActivityTimer() {
602 if (!gUserInteractionTimerCallback) return NS_OK;
603
604 if (!gUserInteractionTimer) {
605 gUserInteractionTimer = NS_NewTimer().take();
606 }
607
608 if (gUserInteractionTimer) {
609 gUserInteractionTimer->InitWithCallback(
610 gUserInteractionTimerCallback,
611 StaticPrefs::dom_events_user_interaction_interval(),
612 nsITimer::TYPE_ONE_SHOT);
613 }
614 return NS_OK;
615}
616
617nsresult EventStateManager::Init() {
618 nsCOMPtr<nsIObserverService> observerService =
619 mozilla::services::GetObserverService();
620 if (!observerService) return NS_ERROR_FAILURE;
621
622 observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown", true);
623
624 return NS_OK;
625}
626
627bool EventStateManager::ShouldAlwaysUseLineDeltas() {
628 if (MOZ_UNLIKELY(!mShouldAlwaysUseLineDeltasInitialized)(__builtin_expect(!!(!mShouldAlwaysUseLineDeltasInitialized),
0))
) {
629 mShouldAlwaysUseLineDeltasInitialized = true;
630 mShouldAlwaysUseLineDeltas =
631 !StaticPrefs::dom_event_wheel_deltaMode_lines_disabled();
632 if (!mShouldAlwaysUseLineDeltas && mDocument) {
633 if (nsIPrincipal* principal =
634 mDocument->GetPrincipalForPrefBasedHacks()) {
635 mShouldAlwaysUseLineDeltas = principal->IsURIInPrefList(
636 "dom.event.wheel-deltaMode-lines.always-enabled");
637 }
638 }
639 }
640 return mShouldAlwaysUseLineDeltas;
641}
642
643EventStateManager::~EventStateManager() {
644 ReleaseCurrentIMEContentObserver();
645
646 if (sActiveESM == this) {
647 sActiveESM = nullptr;
648 }
649
650 if (StaticPrefs::ui_click_hold_context_menus()) {
651 KillClickHoldTimer();
652 }
653
654 if (sCursorSettingManager == this) {
655 sCursorSettingManager = nullptr;
656 }
657
658 --sESMInstanceCount;
659 if (sESMInstanceCount == 0) {
660 WheelTransaction::Shutdown();
661 if (gUserInteractionTimerCallback) {
662 gUserInteractionTimerCallback->Notify(nullptr);
663 NS_RELEASE(gUserInteractionTimerCallback)do { (gUserInteractionTimerCallback)->Release(); (gUserInteractionTimerCallback
) = 0; } while (0)
;
664 }
665 if (gUserInteractionTimer) {
666 gUserInteractionTimer->Cancel();
667 NS_RELEASE(gUserInteractionTimer)do { (gUserInteractionTimer)->Release(); (gUserInteractionTimer
) = 0; } while (0)
;
668 }
669 WheelPrefs::Shutdown();
670 DeltaAccumulator::Shutdown();
671 }
672
673 if (sDragOverContent && sDragOverContent->OwnerDoc() == mDocument) {
674 sDragOverContent = nullptr;
675 }
676
677 if (!m_haveShutdown) {
678 Shutdown();
679
680 // Don't remove from Observer service in Shutdown because Shutdown also
681 // gets called from xpcom shutdown observer. And we don't want to remove
682 // from the service in that case.
683
684 nsCOMPtr<nsIObserverService> observerService =
685 mozilla::services::GetObserverService();
686 if (observerService) {
687 observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown");
688 }
689 }
690}
691
692nsresult EventStateManager::Shutdown() {
693 m_haveShutdown = true;
694 return NS_OK;
695}
696
697NS_IMETHODIMPnsresult
698EventStateManager::Observe(nsISupports* aSubject, const char* aTopic,
699 const char16_t* someData) {
700 if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown")) {
701 Shutdown();
702 }
703
704 return NS_OK;
705}
706
707NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(EventStateManager)nsresult EventStateManager::QueryInterface(const nsIID& aIID
, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 707); MOZ_PretendNoReturn(); } } while (0); nsISupports* foundInterface
; if (TopThreeWordsEquals( aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID), (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID)) && (LowWordEquals(aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID)) || LowWordEquals(aIID, (nsCycleCollectionISupports::COMTypeInfo
<nsCycleCollectionISupports, void>::kIID)))) { if (LowWordEquals
(aIID, (nsXPCOMCycleCollectionParticipant::COMTypeInfo<nsXPCOMCycleCollectionParticipant
, void>::kIID))) { *aInstancePtr = EventStateManager::cycleCollection
::GetParticipant(); return NS_OK; } if (LowWordEquals(aIID, (
nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID))) { *aInstancePtr = EventStateManager::cycleCollection
::Upcast(this); return NS_OK; } foundInterface = nullptr; } else
708 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupports>)) foundInterface = static_cast
<nsISupports*>(static_cast<nsIObserver*>(this)); else
709 NS_INTERFACE_MAP_ENTRY(nsIObserver)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIObserver>)) foundInterface = static_cast
<nsIObserver*>(this); else
710 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupportsWeakReference>)) foundInterface
= static_cast<nsISupportsWeakReference*>(this); else
711NS_INTERFACE_MAP_ENDfoundInterface = 0; nsresult status; if (!foundInterface) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(!aIID.Equals((nsISupports::COMTypeInfo<nsISupports
, void>::kIID)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aIID.Equals((nsISupports::COMTypeInfo
<nsISupports, void>::kIID))))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 711); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
")"); do { *((volatile int*)__null) = 711; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); status = NS_NOINTERFACE
; } else { (foundInterface)->AddRef(); status = NS_OK; } *
aInstancePtr = foundInterface; return status; }
712
713NS_IMPL_CYCLE_COLLECTING_ADDREF(EventStateManager)MozExternalRefCountType EventStateManager::AddRef(void) { static_assert
(!std::is_destructible_v<EventStateManager>, "Reference-counted class "
"EventStateManager" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 713); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
713; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); _mOwningThread.AssertOwnership("EventStateManager"
" not thread-safe"); nsISupports* base = EventStateManager::
cycleCollection::Upcast(this); nsrefcnt count = mRefCnt.incr(
base); NS_LogAddRef((this), (count), ("EventStateManager"), (
uint32_t)(sizeof(*this))); return count; }
714NS_IMPL_CYCLE_COLLECTING_RELEASE(EventStateManager)MozExternalRefCountType EventStateManager::Release(void) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 714); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 714
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); _mOwningThread.AssertOwnership("EventStateManager" " not thread-safe"
); nsISupports* base = EventStateManager::cycleCollection::Upcast
(this); nsrefcnt count = mRefCnt.decr(base); NS_LogRelease((this
), (count), ("EventStateManager")); return count; } void EventStateManager
::DeleteCycleCollectable(void) { delete (this); }
715
716NS_IMPL_CYCLE_COLLECTION_WEAK(EventStateManager, mCurrentTargetContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
717 mGestureDownContent, mGestureDownFrameOwner,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
718 mLastLeftMouseDownInfo.mLastMouseDownContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
719 mLastMiddleMouseDownInfo.mLastMouseDownContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
720 mLastRightMouseDownInfo.mLastMouseDownContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
721 mActiveContent, mHoverContent, mURLTargetContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
722 mPopoverPointerDownTarget, mMouseEnterLeaveHelper,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
723 mPointersEnterLeaveHelper, mDocument,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
724 mIMEContentObserver, mAccessKeys)EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
725
726void EventStateManager::ReleaseCurrentIMEContentObserver() {
727 if (mIMEContentObserver) {
728 mIMEContentObserver->DisconnectFromEventStateManager();
729 }
730 mIMEContentObserver = nullptr;
731}
732
733void EventStateManager::OnStartToObserveContent(
734 IMEContentObserver* aIMEContentObserver) {
735 if (mIMEContentObserver == aIMEContentObserver) {
736 return;
737 }
738 ReleaseCurrentIMEContentObserver();
739 mIMEContentObserver = aIMEContentObserver;
740}
741
742void EventStateManager::OnStopObservingContent(
743 IMEContentObserver* aIMEContentObserver) {
744 aIMEContentObserver->DisconnectFromEventStateManager();
745 NS_ENSURE_TRUE_VOID(mIMEContentObserver == aIMEContentObserver)do { if ((__builtin_expect(!!(!(mIMEContentObserver == aIMEContentObserver
)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mIMEContentObserver == aIMEContentObserver"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 745); return; } } while (false)
;
746 mIMEContentObserver = nullptr;
747}
748
749void EventStateManager::TryToFlushPendingNotificationsToIME() {
750 if (mIMEContentObserver) {
751 mIMEContentObserver->TryToFlushPendingNotifications(true);
752 }
753}
754
755static bool IsMessageMouseUserActivity(EventMessage aMessage) {
756 return aMessage == eMouseMove || aMessage == eMouseUp ||
757 aMessage == eMouseDown || aMessage == ePointerAuxClick ||
758 aMessage == eMouseDoubleClick || aMessage == ePointerClick ||
759 aMessage == eMouseActivate || aMessage == eMouseLongTap;
760}
761
762static bool IsMessageGamepadUserActivity(EventMessage aMessage) {
763 return aMessage == eGamepadButtonDown || aMessage == eGamepadButtonUp ||
764 aMessage == eGamepadAxisMove;
765}
766
767// static
768bool EventStateManager::IsKeyboardEventUserActivity(WidgetEvent* aEvent) {
769 // We ignore things that shouldn't cause popups, but also things that look
770 // like shortcut presses. In some obscure cases these may actually be
771 // website input, but any meaningful website will have other input anyway,
772 // and we can't very well tell whether shortcut input was supposed to be
773 // directed at chrome or the document.
774
775 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
776 // Access keys should be treated as page interaction.
777 if (keyEvent->ModifiersMatchWithAccessKey(AccessKeyType::eContent)) {
778 return true;
779 }
780 if (!keyEvent->CanTreatAsUserInput() || keyEvent->IsControl() ||
781 keyEvent->IsMeta() || keyEvent->IsAlt()) {
782 return false;
783 }
784 // Deal with function keys:
785 switch (keyEvent->mKeyNameIndex) {
786 case KEY_NAME_INDEX_F1:
787 case KEY_NAME_INDEX_F2:
788 case KEY_NAME_INDEX_F3:
789 case KEY_NAME_INDEX_F4:
790 case KEY_NAME_INDEX_F5:
791 case KEY_NAME_INDEX_F6:
792 case KEY_NAME_INDEX_F7:
793 case KEY_NAME_INDEX_F8:
794 case KEY_NAME_INDEX_F9:
795 case KEY_NAME_INDEX_F10:
796 case KEY_NAME_INDEX_F11:
797 case KEY_NAME_INDEX_F12:
798 case KEY_NAME_INDEX_F13:
799 case KEY_NAME_INDEX_F14:
800 case KEY_NAME_INDEX_F15:
801 case KEY_NAME_INDEX_F16:
802 case KEY_NAME_INDEX_F17:
803 case KEY_NAME_INDEX_F18:
804 case KEY_NAME_INDEX_F19:
805 case KEY_NAME_INDEX_F20:
806 case KEY_NAME_INDEX_F21:
807 case KEY_NAME_INDEX_F22:
808 case KEY_NAME_INDEX_F23:
809 case KEY_NAME_INDEX_F24:
810 return false;
811 default:
812 return true;
813 }
814}
815
816static void OnTypingInteractionEnded() {
817 // We don't consider a single keystroke to be typing.
818 if (gTypingInteractionKeyPresses > 1) {
819 gTypingInteraction.mInteractionCount += gTypingInteractionKeyPresses;
820 gTypingInteraction.mInteractionTimeInMilliseconds += static_cast<uint32_t>(
821 std::ceil((gTypingEndTime - gTypingStartTime).ToMilliseconds()));
822 }
823
824 gTypingInteractionKeyPresses = 0;
825 gTypingStartTime = TimeStamp();
826 gTypingEndTime = TimeStamp();
827}
828
829static void HandleKeyUpInteraction(WidgetKeyboardEvent* aKeyEvent) {
830 if (EventStateManager::IsKeyboardEventUserActivity(aKeyEvent)) {
831 TimeStamp now = TimeStamp::Now();
832 if (gTypingEndTime.IsNull()) {
833 gTypingEndTime = now;
834 }
835 TimeDuration delay = now - gTypingEndTime;
836 // Has it been too long since the last keystroke to be considered typing?
837 if (gTypingInteractionKeyPresses > 0 &&
838 delay >
839 TimeDuration::FromMilliseconds(
840 StaticPrefs::browser_places_interactions_typing_timeout_ms())) {
841 OnTypingInteractionEnded();
842 }
843 gTypingInteractionKeyPresses++;
844 if (gTypingStartTime.IsNull()) {
845 gTypingStartTime = now;
846 }
847 gTypingEndTime = now;
848 }
849}
850
851nsresult EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
852 WidgetEvent* aEvent,
853 nsIFrame* aTargetFrame,
854 nsIContent* aTargetContent,
855 nsEventStatus* aStatus,
856 nsIContent* aOverrideClickTarget) {
857 AUTO_PROFILER_LABEL("EventStateManager::PreHandleEvent", DOM)mozilla::AutoProfilerLabel raiiObject857( "EventStateManager::PreHandleEvent"
, nullptr, JS::ProfilingCategoryPair::DOM)
;
858 NS_ENSURE_ARG_POINTER(aStatus)do { if ((__builtin_expect(!!(!(aStatus)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStatus" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 858); return NS_ERROR_INVALID_POINTER; } } while (false)
;
859 NS_ENSURE_ARG(aPresContext)do { if ((__builtin_expect(!!(!(aPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 859); return NS_ERROR_INVALID_ARG; } } while (false)
;
860 if (!aEvent) {
861 NS_ERROR("aEvent is null. This should never happen.")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "aEvent is null. This should never happen."
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 861); MOZ_PretendNoReturn(); } while (0)
;
862 return NS_ERROR_NULL_POINTER;
863 }
864
865 NS_WARNING_ASSERTION(do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
866 !aTargetFrame || !aTargetFrame->GetContent() ||do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
867 aTargetFrame->GetContent() == aTargetContent ||do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
868 aTargetFrame->GetContent()->GetFlattenedTreeParent() ==do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
869 aTargetContent ||do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
870 aTargetFrame->IsGeneratedContentFrame(),do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
871 "aTargetFrame should be related with aTargetContent")do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
;
872#if DEBUG1
873 if (aTargetFrame && aTargetFrame->IsGeneratedContentFrame()) {
874 nsCOMPtr<nsIContent> targetContent;
875 aTargetFrame->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
876 MOZ_ASSERT(aTargetContent == targetContent,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTargetContent == targetContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTargetContent == targetContent
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aTargetContent == targetContent" " (" "Unexpected target for generated content frame!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTargetContent == targetContent"
") (" "Unexpected target for generated content frame!" ")");
do { *((volatile int*)__null) = 877; __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
877 "Unexpected target for generated content frame!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTargetContent == targetContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTargetContent == targetContent
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aTargetContent == targetContent" " (" "Unexpected target for generated content frame!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTargetContent == targetContent"
") (" "Unexpected target for generated content frame!" ")");
do { *((volatile int*)__null) = 877; __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
878 }
879#endif
880
881 mCurrentTarget = aTargetFrame;
882 mCurrentTargetContent = nullptr;
883
884 // Do not take account eMouseEnterIntoWidget/ExitFromWidget so that loading
885 // a page when user is not active doesn't change the state to active.
886 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
887 if (aEvent->IsTrusted() &&
888 ((mouseEvent && mouseEvent->IsReal() &&
889 IsMessageMouseUserActivity(mouseEvent->mMessage)) ||
890 aEvent->mClass == eWheelEventClass ||
891 aEvent->mClass == ePointerEventClass ||
892 aEvent->mClass == eTouchEventClass ||
893 aEvent->mClass == eKeyboardEventClass ||
894 (aEvent->mClass == eDragEventClass && aEvent->mMessage == eDrop) ||
895 IsMessageGamepadUserActivity(aEvent->mMessage))) {
896 if (gMouseOrKeyboardEventCounter == 0) {
897 nsCOMPtr<nsIObserverService> obs =
898 mozilla::services::GetObserverService();
899 if (obs) {
900 obs->NotifyObservers(nullptr, "user-interaction-active", nullptr);
901 UpdateUserActivityTimer();
902 }
903 }
904 ++gMouseOrKeyboardEventCounter;
905
906 nsCOMPtr<nsINode> node = aTargetContent;
907 if (node &&
908 ((aEvent->mMessage == eKeyUp && IsKeyboardEventUserActivity(aEvent)) ||
909 aEvent->mMessage == eMouseUp || aEvent->mMessage == eWheel ||
910 aEvent->mMessage == eTouchEnd || aEvent->mMessage == ePointerUp ||
911 aEvent->mMessage == eDrop)) {
912 Document* doc = node->OwnerDoc();
913 while (doc) {
914 doc->SetUserHasInteracted();
915 doc = nsContentUtils::IsChildOfSameType(doc)
916 ? doc->GetInProcessParentDocument()
917 : nullptr;
918 }
919 }
920 }
921
922 WheelTransaction::OnEvent(aEvent);
923
924 // Focus events don't necessarily need a frame.
925 if (!mCurrentTarget && !aTargetContent) {
926 NS_ERROR("mCurrentTarget and aTargetContent are null")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "mCurrentTarget and aTargetContent are null"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 926); MOZ_PretendNoReturn(); } while (0)
;
927 return NS_ERROR_NULL_POINTER;
928 }
929#ifdef DEBUG1
930 if (aEvent->HasDragEventMessage() && PointerLockManager::IsLocked()) {
931 NS_ASSERTION(PointerLockManager::IsLocked(),do { if (!(PointerLockManager::IsLocked())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Pointer is locked. Drag events should be suppressed when "
"the pointer is locked.", "PointerLockManager::IsLocked()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 933); MOZ_PretendNoReturn(); } } while (0)
932 "Pointer is locked. Drag events should be suppressed when "do { if (!(PointerLockManager::IsLocked())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Pointer is locked. Drag events should be suppressed when "
"the pointer is locked.", "PointerLockManager::IsLocked()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 933); MOZ_PretendNoReturn(); } } while (0)
933 "the pointer is locked.")do { if (!(PointerLockManager::IsLocked())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Pointer is locked. Drag events should be suppressed when "
"the pointer is locked.", "PointerLockManager::IsLocked()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 933); MOZ_PretendNoReturn(); } } while (0)
;
934 }
935#endif
936 // Store last known screenPoint and clientPoint so pointer lock
937 // can use these values as constants.
938 if (aEvent->IsTrusted() &&
939 ((mouseEvent && mouseEvent->IsReal()) ||
940 aEvent->mClass == eWheelEventClass) &&
941 !PointerLockManager::IsLocked()) {
942 // XXX Probably doesn't matter much, but storing these in CSS pixels instead
943 // of device pixels means behavior can be a bit odd if you zoom while
944 // pointer-locked.
945 sLastScreenPoint =
946 Event::GetScreenCoords(aPresContext, aEvent, aEvent->mRefPoint)
947 .extract();
948 sLastClientPoint = Event::GetClientCoords(
949 aPresContext, aEvent, aEvent->mRefPoint, CSSIntPoint(0, 0));
950 }
951
952 *aStatus = nsEventStatus_eIgnore;
953
954 if (aEvent->mClass == eQueryContentEventClass) {
955 HandleQueryContentEvent(aEvent->AsQueryContentEvent());
956 return NS_OK;
957 }
958
959 WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
960 if (touchEvent && mInTouchDrag) {
961 if (touchEvent->mMessage == eTouchMove) {
962 GenerateDragGesture(aPresContext, touchEvent);
963 } else {
964 mInTouchDrag = false;
965 StopTrackingDragGesture(true);
966 }
967 }
968
969 if (mMouseEnterLeaveHelper && aEvent->IsTrusted()) {
970 // When the last `mouseover` event target is removed from the document,
971 // we makes mMouseEnterLeaveHelper update the last deepest `mouseenter`
972 // event target to the removed node parent and mark it as not the following
973 // `mouseout` event target. However, the other browsers may dispatch
974 // `mouseout` on it if it's restored "immediately". Therefore, we use
975 // the next animation frame as the deadline. ContentRemoved() enqueues a
976 // synthesized `mousemove` to dispatch mouse boundary events under the
977 // mouse cursor soon and the synthesized event (or eMouseExitFromWidget if
978 // our window is moved) will reach here at latest the next animation frame.
979 // Therefore, we can use the event as the deadline. If the removed last
980 // `mouseover` target is reconnected before a synthesized mouse event or
981 // a real mouse event, let's restore it as the following `mouseout` event
982 // target. Otherwise, e.g., a keyboard event, let's forget it.
983 mMouseEnterLeaveHelper->TryToRestorePendingRemovedOverTarget(aEvent);
984 }
985
986 static constexpr auto const allowSynthesisForTests = []() -> bool {
987 nsCOMPtr<nsIDragService> dragService =
988 do_GetService("@mozilla.org/widget/dragservice;1");
989 return dragService &&
990 !dragService->GetNeverAllowSessionIsSynthesizedForTests();
991 };
992
993 switch (aEvent->mMessage) {
994 case eContextMenu:
995 if (PointerLockManager::IsLocked()) {
996 return NS_ERROR_DOM_INVALID_STATE_ERR;
997 }
998 break;
999 case eMouseTouchDrag:
1000 mInTouchDrag = true;
1001 BeginTrackingDragGesture(aPresContext, mouseEvent, aTargetFrame);
1002 break;
1003 case eMouseDown: {
1004 switch (mouseEvent->mButton) {
1005 case MouseButton::ePrimary:
1006 BeginTrackingDragGesture(aPresContext, mouseEvent, aTargetFrame);
1007 mLastLeftMouseDownInfo.mClickCount = mouseEvent->mClickCount;
1008 SetClickCount(mouseEvent, aStatus);
1009 sNormalLMouseEventInProcess = true;
1010 break;
1011 case MouseButton::eMiddle:
1012 mLastMiddleMouseDownInfo.mClickCount = mouseEvent->mClickCount;
1013 SetClickCount(mouseEvent, aStatus);
1014 break;
1015 case MouseButton::eSecondary:
1016 mLastRightMouseDownInfo.mClickCount = mouseEvent->mClickCount;
1017 SetClickCount(mouseEvent, aStatus);
1018 break;
1019 }
1020 if (!StaticPrefs::dom_popup_experimental()) {
1021 NotifyTargetUserActivation(aEvent, aTargetContent);
1022 }
1023 break;
1024 }
1025 case eMouseUp: {
1026 switch (mouseEvent->mButton) {
1027 case MouseButton::ePrimary:
1028 if (StaticPrefs::ui_click_hold_context_menus()) {
1029 KillClickHoldTimer();
1030 }
1031 mInTouchDrag = false;
1032 StopTrackingDragGesture(true);
1033 sNormalLMouseEventInProcess = false;
1034 // then fall through...
1035 [[fallthrough]];
1036 case MouseButton::eSecondary:
1037 case MouseButton::eMiddle:
1038 RefPtr<EventStateManager> esm =
1039 ESMFromContentOrThis(aOverrideClickTarget);
1040 esm->SetClickCount(mouseEvent, aStatus, aOverrideClickTarget);
1041 break;
1042 }
1043 break;
1044 }
1045 case eMouseEnterIntoWidget:
1046 PointerEventHandler::UpdateActivePointerState(mouseEvent, aTargetContent);
1047 // In some cases on e10s eMouseEnterIntoWidget
1048 // event was sent twice into child process of content.
1049 // (From specific widget code (sending is not permanent) and
1050 // from ESM::DispatchMouseOrPointerBoundaryEvent (sending is permanent)).
1051 // IsCrossProcessForwardingStopped() helps to suppress sending accidental
1052 // event from widget code.
1053 aEvent->StopCrossProcessForwarding();
1054 break;
1055 case eMouseExitFromWidget:
1056 // If this is a remote frame, we receive eMouseExitFromWidget from the
1057 // parent the mouse exits our content. Since the parent may update the
1058 // cursor while the mouse is outside our frame, and since PuppetWidget
1059 // caches the current cursor internally, re-entering our content (say from
1060 // over a window edge) wont update the cursor if the cached value and the
1061 // current cursor match. So when the mouse exits a remote frame, clear the
1062 // cached widget cursor so a proper update will occur when the mouse
1063 // re-enters.
1064 if (XRE_IsContentProcess()) {
1065 ClearCachedWidgetCursor(mCurrentTarget);
1066 }
1067
1068 // IsCrossProcessForwardingStopped() helps to suppress double event
1069 // sending into process of content. For more information see comment
1070 // above, at eMouseEnterIntoWidget case.
1071 aEvent->StopCrossProcessForwarding();
1072
1073 // If the event is not a top-level window or puppet widget exit, then it's
1074 // not really an exit --- we may have traversed widget boundaries but
1075 // we're still in our toplevel window or puppet widget.
1076 if (mouseEvent->mExitFrom.value() !=
1077 WidgetMouseEvent::ePlatformTopLevel &&
1078 mouseEvent->mExitFrom.value() != WidgetMouseEvent::ePuppet) {
1079 // Treat it as a synthetic move so we don't generate spurious
1080 // "exit" or "move" events. Any necessary "out" or "over" events
1081 // will be generated by GenerateMouseEnterExit
1082 mouseEvent->mMessage = eMouseMove;
1083 mouseEvent->mReason = WidgetMouseEvent::eSynthesized;
1084 // then fall through...
1085 } else {
1086 MOZ_ASSERT_IF(XRE_IsParentProcess(),do { if (XRE_IsParentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePlatformTopLevel)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1088); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
")"); do { *((volatile int*)__null) = 1088; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1087 mouseEvent->mExitFrom.value() ==do { if (XRE_IsParentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePlatformTopLevel)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1088); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
")"); do { *((volatile int*)__null) = 1088; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1088 WidgetMouseEvent::ePlatformTopLevel)do { if (XRE_IsParentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePlatformTopLevel)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1088); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
")"); do { *((volatile int*)__null) = 1088; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1089 MOZ_ASSERT_IF(XRE_IsContentProcess(), mouseEvent->mExitFrom.value() ==do { if (XRE_IsContentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePuppet)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mouseEvent->mExitFrom.value
() == WidgetMouseEvent::ePuppet))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1090); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
")"); do { *((volatile int*)__null) = 1090; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1090 WidgetMouseEvent::ePuppet)do { if (XRE_IsContentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePuppet)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mouseEvent->mExitFrom.value
() == WidgetMouseEvent::ePuppet))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1090); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
")"); do { *((volatile int*)__null) = 1090; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1091 // We should synthetize corresponding pointer events
1092 GeneratePointerEnterExit(ePointerLeave, mouseEvent);
1093 GenerateMouseEnterExit(mouseEvent);
1094 // This is really an exit and should stop here
1095 aEvent->mMessage = eVoidEvent;
1096 break;
1097 }
1098 [[fallthrough]];
1099 case eMouseMove:
1100 case ePointerDown:
1101 if (aEvent->mMessage == ePointerDown) {
1102 PointerEventHandler::UpdateActivePointerState(mouseEvent,
1103 aTargetContent);
1104 PointerEventHandler::ImplicitlyCapturePointer(aTargetFrame, aEvent);
1105 if (StaticPrefs::dom_popup_experimental()) {
1106 // https://html.spec.whatwg.org/multipage/interaction.html#activation-triggering-input-event
1107 if (mouseEvent->mInputSource ==
1108 MouseEvent_Binding::MOZ_SOURCE_MOUSE) {
1109 NotifyTargetUserActivation(aEvent, aTargetContent);
1110 }
1111 } else if (mouseEvent->mInputSource !=
1112 MouseEvent_Binding::MOZ_SOURCE_TOUCH) {
1113 NotifyTargetUserActivation(aEvent, aTargetContent);
1114 }
1115
1116 LightDismissOpenPopovers(aEvent, aTargetContent);
1117 }
1118 [[fallthrough]];
1119 case ePointerMove: {
1120 if (!mInTouchDrag &&
1121 PointerEventHandler::IsDragAndDropEnabled(*mouseEvent)) {
1122 GenerateDragGesture(aPresContext, mouseEvent);
1123 }
1124 // on the Mac, GenerateDragGesture() may not return until the drag
1125 // has completed and so |aTargetFrame| may have been deleted (moving
1126 // a bookmark, for example). If this is the case, however, we know
1127 // that ClearFrameRefs() has been called and it cleared out
1128 // |mCurrentTarget|. As a result, we should pass |mCurrentTarget|
1129 // into UpdateCursor().
1130 UpdateCursor(aPresContext, mouseEvent, mCurrentTarget, aStatus);
1131
1132 UpdateLastRefPointOfMouseEvent(mouseEvent);
1133 if (PointerLockManager::IsLocked()) {
1134 ResetPointerToWindowCenterWhilePointerLocked(mouseEvent);
1135 }
1136 UpdateLastPointerPosition(mouseEvent);
1137
1138 GenerateMouseEnterExit(mouseEvent);
1139 // Flush pending layout changes, so that later mouse move events
1140 // will go to the right nodes.
1141 FlushLayout(aPresContext);
1142 break;
1143 }
1144 case ePointerUp:
1145 LightDismissOpenPopovers(aEvent, aTargetContent);
1146 GenerateMouseEnterExit(mouseEvent);
1147 if (StaticPrefs::dom_popup_experimental() &&
1148 mouseEvent->mInputSource != MouseEvent_Binding::MOZ_SOURCE_MOUSE) {
1149 NotifyTargetUserActivation(aEvent, aTargetContent);
1150 }
1151 break;
1152 case ePointerGotCapture:
1153 GenerateMouseEnterExit(mouseEvent);
1154 break;
1155 case eDragStart:
1156 if (StaticPrefs::ui_click_hold_context_menus()) {
1157 // an external drag gesture event came in, not generated internally
1158 // by Gecko. Make sure we get rid of the click-hold timer.
1159 KillClickHoldTimer();
1160 }
1161 break;
1162 case eDragOver: {
1163 WidgetDragEvent* dragEvent = aEvent->AsDragEvent();
1164 MOZ_ASSERT(dragEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(dragEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(dragEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("dragEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1164); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dragEvent" ")"
); do { *((volatile int*)__null) = 1164; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1165 if (dragEvent->mFlags.mIsSynthesizedForTests &&
1166 allowSynthesisForTests()) {
1167 dragEvent->InitDropEffectForTests();
1168 }
1169 // Send the enter/exit events before eDrop.
1170 GenerateDragDropEnterExit(aPresContext, dragEvent);
1171 break;
1172 }
1173 case eDrop: {
1174 if (aEvent->mFlags.mIsSynthesizedForTests && allowSynthesisForTests()) {
1175 MOZ_ASSERT(aEvent->AsDragEvent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->AsDragEvent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->AsDragEvent()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->AsDragEvent()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1175); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->AsDragEvent()"
")"); do { *((volatile int*)__null) = 1175; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1176 aEvent->AsDragEvent()->InitDropEffectForTests();
1177 }
1178 break;
1179 }
1180 case eKeyPress: {
1181 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
1182 if (keyEvent->ModifiersMatchWithAccessKey(AccessKeyType::eChrome) ||
1183 keyEvent->ModifiersMatchWithAccessKey(AccessKeyType::eContent)) {
1184 // If the eKeyPress event will be sent to a remote process, this
1185 // process needs to wait reply from the remote process for checking if
1186 // preceding eKeyDown event is consumed. If preceding eKeyDown event
1187 // is consumed in the remote process, BrowserChild won't send the event
1188 // back to this process. So, only when this process receives a reply
1189 // eKeyPress event in BrowserParent, we should handle accesskey in this
1190 // process.
1191 if (IsTopLevelRemoteTarget(GetFocusedElement())) {
1192 // However, if there is no accesskey target for the key combination,
1193 // we don't need to wait reply from the remote process. Otherwise,
1194 // Mark the event as waiting reply from remote process and stop
1195 // propagation in this process.
1196 if (CheckIfEventMatchesAccessKey(keyEvent, aPresContext)) {
1197 keyEvent->StopPropagation();
1198 keyEvent->MarkAsWaitingReplyFromRemoteProcess();
1199 }
1200 }
1201 // If the event target is in this process, we can handle accesskey now
1202 // since if preceding eKeyDown event was consumed, eKeyPress event
1203 // won't be dispatched by widget. So, coming eKeyPress event means
1204 // that the preceding eKeyDown event wasn't consumed in this case.
1205 else {
1206 AutoTArray<uint32_t, 10> accessCharCodes;
1207 keyEvent->GetAccessKeyCandidates(accessCharCodes);
1208
1209 if (HandleAccessKey(keyEvent, aPresContext, accessCharCodes)) {
1210 *aStatus = nsEventStatus_eConsumeNoDefault;
1211 }
1212 }
1213 }
1214 }
1215 // then fall through...
1216 [[fallthrough]];
1217 case eKeyDown:
1218 if (aEvent->mMessage == eKeyDown) {
1219 NotifyTargetUserActivation(aEvent, aTargetContent);
1220 }
1221 [[fallthrough]];
1222 case eKeyUp: {
1223 Element* element = GetFocusedElement();
1224 if (element) {
1225 mCurrentTargetContent = element;
1226 }
1227
1228 // NOTE: Don't refer TextComposition::IsComposing() since UI Events
1229 // defines that KeyboardEvent.isComposing is true when it's
1230 // dispatched after compositionstart and compositionend.
1231 // TextComposition::IsComposing() is false even before
1232 // compositionend if there is no composing string.
1233 // And also don't expose other document's composition state.
1234 // A native IME context is typically shared by multiple documents.
1235 // So, don't use GetTextCompositionFor(nsIWidget*) here.
1236 RefPtr<TextComposition> composition =
1237 IMEStateManager::GetTextCompositionFor(aPresContext);
1238 aEvent->AsKeyboardEvent()->mIsComposing = !!composition;
1239
1240 // Widget may need to perform default action for specific keyboard
1241 // event if it's not consumed. In this case, widget has already marked
1242 // the event as "waiting reply from remote process". However, we need
1243 // to reset it if the target (focused content) isn't in a remote process
1244 // because PresShell needs to check if it's marked as so before
1245 // dispatching events into the DOM tree.
1246 if (aEvent->IsWaitingReplyFromRemoteProcess() &&
1247 !aEvent->PropagationStopped() && !IsTopLevelRemoteTarget(element)) {
1248 aEvent->ResetWaitingReplyFromRemoteProcessState();
1249 }
1250 } break;
1251 case eWheel:
1252 case eWheelOperationStart:
1253 case eWheelOperationEnd: {
1254 NS_ASSERTION(aEvent->IsTrusted(),do { if (!(aEvent->IsTrusted())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Untrusted wheel event shouldn't be here", "aEvent->IsTrusted()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1255); MOZ_PretendNoReturn(); } } while (0)
1255 "Untrusted wheel event shouldn't be here")do { if (!(aEvent->IsTrusted())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Untrusted wheel event shouldn't be here", "aEvent->IsTrusted()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1255); MOZ_PretendNoReturn(); } } while (0)
;
1256 using DeltaModeCheckingState = WidgetWheelEvent::DeltaModeCheckingState;
1257
1258 if (Element* element = GetFocusedElement()) {
1259 mCurrentTargetContent = element;
1260 }
1261
1262 if (aEvent->mMessage != eWheel) {
1263 break;
1264 }
1265
1266 WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
1267 WheelPrefs::GetInstance()->ApplyUserPrefsToDelta(wheelEvent);
1268
1269 // If we won't dispatch a DOM event for this event, nothing to do anymore.
1270 if (!wheelEvent->IsAllowedToDispatchDOMEvent()) {
1271 break;
1272 }
1273
1274 if (StaticPrefs::dom_event_wheel_deltaMode_lines_always_disabled()) {
1275 wheelEvent->mDeltaModeCheckingState = DeltaModeCheckingState::Unchecked;
1276 } else if (ShouldAlwaysUseLineDeltas()) {
1277 wheelEvent->mDeltaModeCheckingState = DeltaModeCheckingState::Checked;
1278 } else {
1279 wheelEvent->mDeltaModeCheckingState = DeltaModeCheckingState::Unknown;
1280 }
1281
1282 // Init lineOrPageDelta values for line scroll events for some devices
1283 // on some platforms which might dispatch wheel events which don't
1284 // have lineOrPageDelta values. And also, if delta values are
1285 // customized by prefs, this recomputes them.
1286 DeltaAccumulator::GetInstance()->InitLineOrPageDelta(aTargetFrame, this,
1287 wheelEvent);
1288 } break;
1289 case eSetSelection: {
1290 RefPtr<Element> focuedElement = GetFocusedElement();
1291 IMEStateManager::HandleSelectionEvent(aPresContext, focuedElement,
1292 aEvent->AsSelectionEvent());
1293 break;
1294 }
1295 case eContentCommandCut:
1296 case eContentCommandCopy:
1297 case eContentCommandPaste:
1298 case eContentCommandDelete:
1299 case eContentCommandUndo:
1300 case eContentCommandRedo:
1301 case eContentCommandPasteTransferable:
1302 case eContentCommandLookUpDictionary:
1303 DoContentCommandEvent(aEvent->AsContentCommandEvent());
1304 break;
1305 case eContentCommandInsertText:
1306 DoContentCommandInsertTextEvent(aEvent->AsContentCommandEvent());
1307 break;
1308 case eContentCommandReplaceText:
1309 DoContentCommandReplaceTextEvent(aEvent->AsContentCommandEvent());
1310 break;
1311 case eContentCommandScroll:
1312 DoContentCommandScrollEvent(aEvent->AsContentCommandEvent());
1313 break;
1314 case eCompositionStart:
1315 if (aEvent->IsTrusted()) {
1316 // If the event is trusted event, set the selected text to data of
1317 // composition event.
1318 WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent();
1319 WidgetQueryContentEvent querySelectedTextEvent(
1320 true, eQuerySelectedText, compositionEvent->mWidget);
1321 HandleQueryContentEvent(&querySelectedTextEvent);
1322 if (querySelectedTextEvent.FoundSelection()) {
1323 compositionEvent->mData = querySelectedTextEvent.mReply->DataRef();
1324 }
1325 NS_ASSERTION(querySelectedTextEvent.Succeeded(),do { if (!(querySelectedTextEvent.Succeeded())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Failed to get selected text", "querySelectedTextEvent.Succeeded()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1326); MOZ_PretendNoReturn(); } } while (0)
1326 "Failed to get selected text")do { if (!(querySelectedTextEvent.Succeeded())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Failed to get selected text", "querySelectedTextEvent.Succeeded()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1326); MOZ_PretendNoReturn(); } } while (0)
;
1327 }
1328 break;
1329 case eTouchStart:
1330 SetGestureDownPoint(aEvent->AsTouchEvent());
1331 break;
1332 case eTouchEnd:
1333 if (!StaticPrefs::dom_popup_experimental()) {
1334 NotifyTargetUserActivation(aEvent, aTargetContent);
1335 }
1336 break;
1337 default:
1338 break;
1339 }
1340 return NS_OK;
1341}
1342
1343// Returns true if this event is likely an user activation for a link or
1344// a link-like button, where modifier keys are likely be used for controlling
1345// where the link is opened.
1346//
1347// The modifiers associated with the user activation is used for controlling
1348// where the `window.open` is opened into.
1349static bool CanReflectModifiersToUserActivation(WidgetInputEvent* aEvent) {
1350 if (StaticPrefs::dom_popup_experimental()) {
1351 MOZ_ASSERT(aEvent->mMessage == eKeyDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1353); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1353; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1352 aEvent->mMessage == ePointerDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1353); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1353; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1353 aEvent->mMessage == ePointerUp)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1353); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1353; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1354 } else {
1355 MOZ_ASSERT(aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1357); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1357; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1356 aEvent->mMessage == ePointerDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1357); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1357; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1357 aEvent->mMessage == eTouchEnd)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1357); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1357; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1358 }
1359
1360 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
1361 if (keyEvent) {
1362 return keyEvent->CanReflectModifiersToUserActivation();
1363 }
1364
1365 return true;
1366}
1367
1368void EventStateManager::NotifyTargetUserActivation(WidgetEvent* aEvent,
1369 nsIContent* aTargetContent) {
1370 if (!aEvent->IsTrusted()) {
1371 return;
1372 }
1373
1374 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
1375 if (mouseEvent && !mouseEvent->IsReal()) {
1376 return;
1377 }
1378
1379 nsCOMPtr<nsINode> node = aTargetContent;
1380 if (!node) {
1381 return;
1382 }
1383
1384 Document* doc = node->OwnerDoc();
1385 if (!doc) {
1386 return;
1387 }
1388
1389 // Don't gesture activate for key events for keys which are likely
1390 // to be interaction with the browser, OS.
1391 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
1392 if (keyEvent && !keyEvent->CanUserGestureActivateTarget()) {
1393 return;
1394 }
1395
1396 // Touch gestures that end outside the drag target were touches that turned
1397 // into scroll/pan/swipe actions. We don't want to gesture activate on such
1398 // actions, we want to only gesture activate on touches that are taps.
1399 // That is, touches that end in roughly the same place that they started.
1400 if ((aEvent->mMessage == eTouchEnd ||
1401 (aEvent->mMessage == ePointerUp &&
1402 aEvent->AsPointerEvent()->mInputSource ==
1403 MouseEvent_Binding::MOZ_SOURCE_TOUCH)) &&
1404 IsEventOutsideDragThreshold(aEvent->AsInputEvent())) {
1405 return;
1406 }
1407
1408 // Do not treat the click on scrollbar as a user interaction with the web
1409 // content.
1410 if (StaticPrefs::dom_user_activation_ignore_scrollbars() &&
1411 ((StaticPrefs::dom_popup_experimental() &&
1412 (aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp)) ||
1413 (!StaticPrefs::dom_popup_experimental() &&
1414 (aEvent->mMessage == eMouseDown ||
1415 aEvent->mMessage == ePointerDown))) &&
1416 aTargetContent->IsInNativeAnonymousSubtree()) {
1417 nsIContent* current = aTargetContent;
1418 do {
1419 nsIContent* root = current->GetClosestNativeAnonymousSubtreeRoot();
1420 if (!root) {
1421 break;
1422 }
1423 if (root->IsXULElement(nsGkAtoms::scrollbar)) {
1424 return;
1425 }
1426 current = root->GetParent();
1427 } while (current);
1428 }
1429
1430#ifdef DEBUG1
1431 if (StaticPrefs::dom_popup_experimental()) {
1432 MOZ_ASSERT(aEvent->mMessage == eKeyDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1434); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1434; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1433 aEvent->mMessage == ePointerDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1434); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1434; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1434 aEvent->mMessage == ePointerUp)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1434); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1434; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1435 } else {
1436 MOZ_ASSERT(aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1438); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1438; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1437 aEvent->mMessage == ePointerDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1438); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1438; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1438 aEvent->mMessage == eTouchEnd)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1438); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1438; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1439 }
1440#endif
1441
1442 UserActivation::Modifiers modifiers;
1443 if (WidgetInputEvent* inputEvent = aEvent->AsInputEvent()) {
1444 if (CanReflectModifiersToUserActivation(inputEvent)) {
1445 if (inputEvent->IsShift()) {
1446 modifiers.SetShift();
1447 }
1448 if (inputEvent->IsMeta()) {
1449 modifiers.SetMeta();
1450 }
1451 if (inputEvent->IsControl()) {
1452 modifiers.SetControl();
1453 }
1454 if (inputEvent->IsAlt()) {
1455 modifiers.SetAlt();
1456 }
1457
1458 WidgetMouseEvent* mouseEvent = inputEvent->AsMouseEvent();
1459 if (mouseEvent) {
1460 if (mouseEvent->mButton == MouseButton::eMiddle) {
1461 modifiers.SetMiddleMouse();
1462 }
1463 }
1464 }
1465 }
1466 doc->NotifyUserGestureActivation(modifiers);
1467}
1468
1469// https://html.spec.whatwg.org/multipage/popover.html#popover-light-dismiss
1470void EventStateManager::LightDismissOpenPopovers(WidgetEvent* aEvent,
1471 nsIContent* aTargetContent) {
1472 MOZ_ASSERT(aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == ePointerDown || aEvent->mMessage
== ePointerUp)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
" (" "Light dismiss must be called for pointer up/down only"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
") (" "Light dismiss must be called for pointer up/down only"
")"); do { *((volatile int*)__null) = 1473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1473 "Light dismiss must be called for pointer up/down only")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == ePointerDown || aEvent->mMessage
== ePointerUp)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
" (" "Light dismiss must be called for pointer up/down only"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
") (" "Light dismiss must be called for pointer up/down only"
")"); do { *((volatile int*)__null) = 1473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1474
1475 if (!StaticPrefs::dom_element_popover_enabled() || !aEvent->IsTrusted() ||
1476 !aTargetContent) {
1477 return;
1478 }
1479
1480 Element* topmostPopover = aTargetContent->OwnerDoc()->GetTopmostAutoPopover();
1481 if (!topmostPopover) {
1482 return;
1483 }
1484
1485 // Pointerdown: set document's popover pointerdown target to the result of
1486 // running topmost clicked popover given target.
1487 if (aEvent->mMessage == ePointerDown) {
1488 mPopoverPointerDownTarget = aTargetContent->GetTopmostClickedPopover();
1489 return;
1490 }
1491
1492 // Pointerup: hide open popovers.
1493 RefPtr<nsINode> ancestor = aTargetContent->GetTopmostClickedPopover();
1494 bool sameTarget = mPopoverPointerDownTarget == ancestor;
1495 mPopoverPointerDownTarget = nullptr;
1496 if (!sameTarget) {
1497 return;
1498 }
1499
1500 if (!ancestor) {
1501 ancestor = aTargetContent->OwnerDoc();
1502 }
1503 RefPtr<Document> doc(ancestor->OwnerDoc());
1504 doc->HideAllPopoversUntil(*ancestor, false, true);
1505}
1506
1507already_AddRefed<EventStateManager> EventStateManager::ESMFromContentOrThis(
1508 nsIContent* aContent) {
1509 if (aContent) {
1510 PresShell* presShell = aContent->OwnerDoc()->GetPresShell();
1511 if (presShell) {
1512 nsPresContext* prescontext = presShell->GetPresContext();
1513 if (prescontext) {
1514 RefPtr<EventStateManager> esm = prescontext->EventStateManager();
1515 if (esm) {
1516 return esm.forget();
1517 }
1518 }
1519 }
1520 }
1521
1522 RefPtr<EventStateManager> esm = this;
1523 return esm.forget();
1524}
1525
1526EventStateManager::LastMouseDownInfo& EventStateManager::GetLastMouseDownInfo(
1527 int16_t aButton) {
1528 switch (aButton) {
1529 case MouseButton::ePrimary:
1530 return mLastLeftMouseDownInfo;
1531 case MouseButton::eMiddle:
1532 return mLastMiddleMouseDownInfo;
1533 case MouseButton::eSecondary:
1534 return mLastRightMouseDownInfo;
1535 default:
1536 MOZ_ASSERT_UNREACHABLE("This button shouldn't use this method")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"This button shouldn't use this method" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1536); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "This button shouldn't use this method"
")"); do { *((volatile int*)__null) = 1536; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1537 return mLastLeftMouseDownInfo;
1538 }
1539}
1540
1541void EventStateManager::HandleQueryContentEvent(
1542 WidgetQueryContentEvent* aEvent) {
1543 switch (aEvent->mMessage) {
1544 case eQuerySelectedText:
1545 case eQueryTextContent:
1546 case eQueryCaretRect:
1547 case eQueryTextRect:
1548 case eQueryEditorRect:
1549 if (!IsTargetCrossProcess(aEvent)) {
1550 break;
1551 }
1552 // Will not be handled locally, remote the event
1553 GetCrossProcessTarget()->HandleQueryContentEvent(*aEvent);
1554 return;
1555 // Following events have not been supported in e10s mode yet.
1556 case eQueryContentState:
1557 case eQuerySelectionAsTransferable:
1558 case eQueryCharacterAtPoint:
1559 case eQueryDOMWidgetHittest:
1560 case eQueryTextRectArray:
1561 case eQueryDropTargetHittest:
1562 break;
1563 default:
1564 return;
1565 }
1566
1567 // If there is an IMEContentObserver, we need to handle QueryContentEvent
1568 // with it.
1569 // eQueryDropTargetHittest is not really an IME event, though
1570 if (mIMEContentObserver && aEvent->mMessage != eQueryDropTargetHittest) {
1571 RefPtr<IMEContentObserver> contentObserver = mIMEContentObserver;
1572 contentObserver->HandleQueryContentEvent(aEvent);
1573 return;
1574 }
1575
1576 ContentEventHandler handler(mPresContext);
1577 handler.HandleQueryContentEvent(aEvent);
1578}
1579
1580static AccessKeyType GetAccessKeyTypeFor(nsISupports* aDocShell) {
1581 nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(aDocShell));
1582 if (!treeItem) {
1583 return AccessKeyType::eNone;
1584 }
1585
1586 switch (treeItem->ItemType()) {
1587 case nsIDocShellTreeItem::typeChrome:
1588 return AccessKeyType::eChrome;
1589 case nsIDocShellTreeItem::typeContent:
1590 return AccessKeyType::eContent;
1591 default:
1592 return AccessKeyType::eNone;
1593 }
1594}
1595
1596static bool IsAccessKeyTarget(Element* aElement, nsAString& aKey) {
1597 // Use GetAttr because we want Unicode case=insensitive matching
1598 // XXXbz shouldn't this be case-sensitive, per spec?
1599 nsString contentKey;
1600 if (!aElement || !aElement->GetAttr(nsGkAtoms::accesskey, contentKey) ||
1601 !contentKey.Equals(aKey, nsCaseInsensitiveStringComparator)) {
1602 return false;
1603 }
1604
1605 if (!aElement->IsXULElement()) {
1606 return true;
1607 }
1608
1609 // For XUL we do visibility checks.
1610 nsIFrame* frame = aElement->GetPrimaryFrame();
1611 if (!frame) {
1612 return false;
1613 }
1614
1615 if (frame->IsFocusable()) {
1616 return true;
1617 }
1618
1619 if (!frame->IsVisibleConsideringAncestors()) {
1620 return false;
1621 }
1622
1623 // XUL controls can be activated.
1624 nsCOMPtr<nsIDOMXULControlElement> control = aElement->AsXULControl();
1625 if (control) {
1626 return true;
1627 }
1628
1629 // XUL label elements are never focusable, so we need to check for them
1630 // explicitly before giving up.
1631 if (aElement->IsXULElement(nsGkAtoms::label)) {
1632 return true;
1633 }
1634
1635 return false;
1636}
1637
1638bool EventStateManager::CheckIfEventMatchesAccessKey(
1639 WidgetKeyboardEvent* aEvent, nsPresContext* aPresContext) {
1640 AutoTArray<uint32_t, 10> accessCharCodes;
1641 aEvent->GetAccessKeyCandidates(accessCharCodes);
1642 return WalkESMTreeToHandleAccessKey(aEvent, aPresContext, accessCharCodes,
1643 nullptr, eAccessKeyProcessingNormal,
1644 false);
1645}
1646
1647bool EventStateManager::LookForAccessKeyAndExecute(
1648 nsTArray<uint32_t>& aAccessCharCodes, bool aIsTrustedEvent, bool aIsRepeat,
1649 bool aExecute) {
1650 int32_t count, start = -1;
1651 if (Element* focusedElement = GetFocusedElement()) {
1652 start = mAccessKeys.IndexOf(focusedElement);
1653 if (start == -1 && focusedElement->IsInNativeAnonymousSubtree()) {
1654 start = mAccessKeys.IndexOf(Element::FromNodeOrNull(
1655 focusedElement->GetClosestNativeAnonymousSubtreeRootParentOrHost()));
1656 }
1657 }
1658 RefPtr<Element> element;
1659 int32_t length = mAccessKeys.Count();
1660 for (uint32_t i = 0; i < aAccessCharCodes.Length(); ++i) {
1661 uint32_t ch = aAccessCharCodes[i];
1662 nsAutoString accessKey;
1663 AppendUCS4ToUTF16(ch, accessKey);
1664 for (count = 1; count <= length; ++count) {
1665 // mAccessKeys always stores Element instances.
1666 MOZ_DIAGNOSTIC_ASSERT(length == mAccessKeys.Count())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(length == mAccessKeys.Count())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(length == mAccessKeys.Count(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("length == mAccessKeys.Count()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1666); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "length == mAccessKeys.Count()"
")"); do { *((volatile int*)__null) = 1666; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1667 element = mAccessKeys[(start + count) % length];
1668 if (IsAccessKeyTarget(element, accessKey)) {
1669 if (!aExecute) {
1670 return true;
1671 }
1672 Document* doc = element->OwnerDoc();
1673 const bool shouldActivate = [&] {
1674 if (!StaticPrefs::accessibility_accesskeycausesactivation()) {
1675 return false;
1676 }
1677 if (aIsRepeat && nsContentUtils::IsChromeDoc(doc)) {
1678 return false;
1679 }
1680
1681 // XXXedgar, Bug 1700646, maybe we could use other data structure to
1682 // make searching target with same accesskey easier, and current setup
1683 // could not ensure we cycle the target with tree order.
1684 int32_t j = 0;
1685 while (++j < length) {
1686 Element* el = mAccessKeys[(start + count + j) % length];
1687 if (IsAccessKeyTarget(el, accessKey)) {
1688 return false;
1689 }
1690 }
1691 return true;
1692 }();
1693
1694 // TODO(bug 1641171): This shouldn't be needed if we considered the
1695 // accesskey combination properly.
1696 if (aIsTrustedEvent) {
1697 doc->NotifyUserGestureActivation();
1698 }
1699
1700 auto result =
1701 element->PerformAccesskey(shouldActivate, aIsTrustedEvent);
1702 if (result.isOk()) {
1703 if (result.unwrap() && aIsTrustedEvent) {
1704 // If this is a child process, inform the parent that we want the
1705 // focus, but pass false since we don't want to change the window
1706 // order.
1707 nsIDocShell* docShell = mPresContext->GetDocShell();
1708 nsCOMPtr<nsIBrowserChild> child =
1709 docShell ? docShell->GetBrowserChild() : nullptr;
1710 if (child) {
1711 child->SendRequestFocus(false, CallerType::System);
1712 }
1713 }
1714 return true;
1715 }
1716 }
1717 }
1718 }
1719 return false;
1720}
1721
1722// static
1723void EventStateManager::GetAccessKeyLabelPrefix(Element* aElement,
1724 nsAString& aPrefix) {
1725 aPrefix.Truncate();
1726 nsAutoString separator, modifierText;
1727 nsContentUtils::GetModifierSeparatorText(separator);
1728
1729 AccessKeyType accessKeyType =
1730 GetAccessKeyTypeFor(aElement->OwnerDoc()->GetDocShell());
1731 if (accessKeyType == AccessKeyType::eNone) {
1732 return;
1733 }
1734 Modifiers modifiers = WidgetKeyboardEvent::AccessKeyModifiers(accessKeyType);
1735 if (modifiers == MODIFIER_NONE) {
1736 return;
1737 }
1738
1739 if (modifiers & MODIFIER_CONTROL) {
1740 nsContentUtils::GetControlText(modifierText);
1741 aPrefix.Append(modifierText + separator);
1742 }
1743 if (modifiers & MODIFIER_META) {
1744 nsContentUtils::GetCommandOrWinText(modifierText);
1745 aPrefix.Append(modifierText + separator);
1746 }
1747 if (modifiers & MODIFIER_ALT) {
1748 nsContentUtils::GetAltText(modifierText);
1749 aPrefix.Append(modifierText + separator);
1750 }
1751 if (modifiers & MODIFIER_SHIFT) {
1752 nsContentUtils::GetShiftText(modifierText);
1753 aPrefix.Append(modifierText + separator);
1754 }
1755}
1756
1757struct MOZ_STACK_CLASS AccessKeyInfo {
1758 WidgetKeyboardEvent* event;
1759 nsTArray<uint32_t>& charCodes;
1760
1761 AccessKeyInfo(WidgetKeyboardEvent* aEvent, nsTArray<uint32_t>& aCharCodes)
1762 : event(aEvent), charCodes(aCharCodes) {}
1763};
1764
1765bool EventStateManager::WalkESMTreeToHandleAccessKey(
1766 WidgetKeyboardEvent* aEvent, nsPresContext* aPresContext,
1767 nsTArray<uint32_t>& aAccessCharCodes, nsIDocShellTreeItem* aBubbledFrom,
1768 ProcessingAccessKeyState aAccessKeyState, bool aExecute) {
1769 EnsureDocument(mPresContext);
1770 nsCOMPtr<nsIDocShell> docShell = aPresContext->GetDocShell();
1771 if (NS_WARN_IF(!docShell)NS_warn_if_impl(!docShell, "!docShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1771)
|| NS_WARN_IF(!mDocument)NS_warn_if_impl(!mDocument, "!mDocument", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1771)
) {
1772 return false;
1773 }
1774 AccessKeyType accessKeyType = GetAccessKeyTypeFor(docShell);
1775 if (accessKeyType == AccessKeyType::eNone) {
1776 return false;
1777 }
1778 // Alt or other accesskey modifier is down, we may need to do an accesskey.
1779 if (mAccessKeys.Count() > 0 &&
1780 aEvent->ModifiersMatchWithAccessKey(accessKeyType)) {
1781 // Someone registered an accesskey. Find and activate it.
1782 if (LookForAccessKeyAndExecute(aAccessCharCodes, aEvent->IsTrusted(),
1783 aEvent->mIsRepeat, aExecute)) {
1784 return true;
1785 }
1786 }
1787
1788 int32_t childCount;
1789 docShell->GetInProcessChildCount(&childCount);
1790 for (int32_t counter = 0; counter < childCount; counter++) {
1791 // Not processing the child which bubbles up the handling
1792 nsCOMPtr<nsIDocShellTreeItem> subShellItem;
1793 docShell->GetInProcessChildAt(counter, getter_AddRefs(subShellItem));
1794 if (aAccessKeyState == eAccessKeyProcessingUp &&
1795 subShellItem == aBubbledFrom) {
1796 continue;
1797 }
1798
1799 nsCOMPtr<nsIDocShell> subDS = do_QueryInterface(subShellItem);
1800 if (subDS && IsShellVisible(subDS)) {
1801 // Guarantee subPresShell lifetime while we're handling access key
1802 // since somebody may assume that it won't be deleted before the
1803 // corresponding nsPresContext and EventStateManager.
1804 RefPtr<PresShell> subPresShell = subDS->GetPresShell();
1805
1806 // Docshells need not have a presshell (eg. display:none
1807 // iframes, docshells in transition between documents, etc).
1808 if (!subPresShell) {
1809 // Oh, well. Just move on to the next child
1810 continue;
1811 }
1812
1813 RefPtr<nsPresContext> subPresContext = subPresShell->GetPresContext();
1814
1815 RefPtr<EventStateManager> esm =
1816 static_cast<EventStateManager*>(subPresContext->EventStateManager());
1817
1818 if (esm && esm->WalkESMTreeToHandleAccessKey(
1819 aEvent, subPresContext, aAccessCharCodes, nullptr,
1820 eAccessKeyProcessingDown, aExecute)) {
1821 return true;
1822 }
1823 }
1824 } // if end . checking all sub docshell ends here.
1825
1826 // bubble up the process to the parent docshell if necessary
1827 if (eAccessKeyProcessingDown != aAccessKeyState) {
1828 nsCOMPtr<nsIDocShellTreeItem> parentShellItem;
1829 docShell->GetInProcessParent(getter_AddRefs(parentShellItem));
1830 nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parentShellItem);
1831 if (parentDS) {
1832 // Guarantee parentPresShell lifetime while we're handling access key
1833 // since somebody may assume that it won't be deleted before the
1834 // corresponding nsPresContext and EventStateManager.
1835 RefPtr<PresShell> parentPresShell = parentDS->GetPresShell();
1836 NS_ASSERTION(parentPresShell,do { if (!(parentPresShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Our PresShell exists but the parent's does not?", "parentPresShell"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1837); MOZ_PretendNoReturn(); } } while (0)
1837 "Our PresShell exists but the parent's does not?")do { if (!(parentPresShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Our PresShell exists but the parent's does not?", "parentPresShell"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1837); MOZ_PretendNoReturn(); } } while (0)
;
1838
1839 RefPtr<nsPresContext> parentPresContext =
1840 parentPresShell->GetPresContext();
1841 NS_ASSERTION(parentPresContext, "PresShell without PresContext")do { if (!(parentPresContext)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "PresShell without PresContext", "parentPresContext", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1841); MOZ_PretendNoReturn(); } } while (0)
;
1842
1843 RefPtr<EventStateManager> esm = static_cast<EventStateManager*>(
1844 parentPresContext->EventStateManager());
1845 if (esm && esm->WalkESMTreeToHandleAccessKey(
1846 aEvent, parentPresContext, aAccessCharCodes, docShell,
1847 eAccessKeyProcessingDown, aExecute)) {
1848 return true;
1849 }
1850 }
1851 } // if end. bubble up process
1852
1853 // If the content access key modifier is pressed, try remote children
1854 if (aExecute &&
1855 aEvent->ModifiersMatchWithAccessKey(AccessKeyType::eContent) &&
1856 mDocument && mDocument->GetWindow()) {
1857 // If the focus is currently on a node with a BrowserParent, the key event
1858 // should've gotten forwarded to the child process and HandleAccessKey
1859 // called from there.
1860 if (BrowserParent::GetFrom(GetFocusedElement())) {
1861 // If access key may be only in remote contents, this method won't handle
1862 // access key synchronously. In this case, only reply event should reach
1863 // here.
1864 MOZ_ASSERT(aEvent->IsHandledInRemoteProcess() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->IsHandledInRemoteProcess() || !aEvent->
IsWaitingReplyFromRemoteProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->IsHandledInRemoteProcess
() || !aEvent->IsWaitingReplyFromRemoteProcess()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aEvent->IsHandledInRemoteProcess() || !aEvent->IsWaitingReplyFromRemoteProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1865); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsHandledInRemoteProcess() || !aEvent->IsWaitingReplyFromRemoteProcess()"
")"); do { *((volatile int*)__null) = 1865; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1865 !aEvent->IsWaitingReplyFromRemoteProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->IsHandledInRemoteProcess() || !aEvent->
IsWaitingReplyFromRemoteProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->IsHandledInRemoteProcess
() || !aEvent->IsWaitingReplyFromRemoteProcess()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aEvent->IsHandledInRemoteProcess() || !aEvent->IsWaitingReplyFromRemoteProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1865); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsHandledInRemoteProcess() || !aEvent->IsWaitingReplyFromRemoteProcess()"
")"); do { *((volatile int*)__null) = 1865; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1866 }
1867 // If focus is somewhere else, then we need to check the remote children.
1868 // However, if the event has already been handled in a remote process,
1869 // then, focus is moved from the remote process after posting the event.
1870 // In such case, we shouldn't retry to handle access keys in remote
1871 // processes.
1872 else if (!aEvent->IsHandledInRemoteProcess()) {
1873 AccessKeyInfo accessKeyInfo(aEvent, aAccessCharCodes);
1874 nsContentUtils::CallOnAllRemoteChildren(
1875 mDocument->GetWindow(),
1876 [&accessKeyInfo](BrowserParent* aBrowserParent) -> CallState {
1877 // Only forward accesskeys for the active tab.
1878 if (aBrowserParent->GetDocShellIsActive()) {
1879 // Even if there is no target for the accesskey in this process,
1880 // the event may match with a content accesskey. If so, the
1881 // keyboard event should be handled with reply event for
1882 // preventing double action. (e.g., Alt+Shift+F on Windows may
1883 // focus a content in remote and open "File" menu.)
1884 accessKeyInfo.event->StopPropagation();
1885 accessKeyInfo.event->MarkAsWaitingReplyFromRemoteProcess();
1886 aBrowserParent->HandleAccessKey(*accessKeyInfo.event,
1887 accessKeyInfo.charCodes);
1888 return CallState::Stop;
1889 }
1890
1891 return CallState::Continue;
1892 });
1893 }
1894 }
1895
1896 return false;
1897} // end of HandleAccessKey
1898
1899static BrowserParent* GetBrowserParentAncestor(BrowserParent* aBrowserParent) {
1900 MOZ_ASSERT(aBrowserParent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aBrowserParent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aBrowserParent))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aBrowserParent"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1900); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aBrowserParent"
")"); do { *((volatile int*)__null) = 1900; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1901
1902 BrowserBridgeParent* bbp = aBrowserParent->GetBrowserBridgeParent();
1903 if (!bbp) {
1904 return nullptr;
1905 }
1906
1907 return bbp->Manager();
1908}
1909
1910static void DispatchCrossProcessMouseExitEvents(WidgetMouseEvent* aMouseEvent,
1911 BrowserParent* aRemoteTarget,
1912 BrowserParent* aStopAncestor,
1913 bool aIsReallyExit) {
1914 MOZ_ASSERT(aMouseEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseEvent))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aMouseEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1914); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseEvent"
")"); do { *((volatile int*)__null) = 1914; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1915 MOZ_ASSERT(aRemoteTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRemoteTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aRemoteTarget))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aRemoteTarget",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1915); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRemoteTarget"
")"); do { *((volatile int*)__null) = 1915; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1916 MOZ_ASSERT(aRemoteTarget != aStopAncestor)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRemoteTarget != aStopAncestor)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aRemoteTarget != aStopAncestor
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aRemoteTarget != aStopAncestor", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1916); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRemoteTarget != aStopAncestor"
")"); do { *((volatile int*)__null) = 1916; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1917 MOZ_ASSERT_IF(aStopAncestor, nsContentUtils::GetCommonBrowserParentAncestor(do { if (aStopAncestor) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(nsContentUtils::GetCommonBrowserParentAncestor
( aRemoteTarget, aStopAncestor))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nsContentUtils::GetCommonBrowserParentAncestor
( aRemoteTarget, aStopAncestor)))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("nsContentUtils::GetCommonBrowserParentAncestor( aRemoteTarget, aStopAncestor)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1918); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::GetCommonBrowserParentAncestor( aRemoteTarget, aStopAncestor)"
")"); do { *((volatile int*)__null) = 1918; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1918 aRemoteTarget, aStopAncestor))do { if (aStopAncestor) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(nsContentUtils::GetCommonBrowserParentAncestor
( aRemoteTarget, aStopAncestor))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nsContentUtils::GetCommonBrowserParentAncestor
( aRemoteTarget, aStopAncestor)))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("nsContentUtils::GetCommonBrowserParentAncestor( aRemoteTarget, aStopAncestor)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1918); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::GetCommonBrowserParentAncestor( aRemoteTarget, aStopAncestor)"
")"); do { *((volatile int*)__null) = 1918; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1919
1920 while (aRemoteTarget != aStopAncestor) {
1921 UniquePtr<WidgetMouseEvent> mouseExitEvent =
1922 CreateMouseOrPointerWidgetEvent(aMouseEvent, eMouseExitFromWidget,
1923 aMouseEvent->mRelatedTarget);
1924 mouseExitEvent->mExitFrom =
1925 Some(aIsReallyExit ? WidgetMouseEvent::ePuppet
1926 : WidgetMouseEvent::ePuppetParentToPuppetChild);
1927 aRemoteTarget->SendRealMouseEvent(*mouseExitEvent);
1928
1929 aRemoteTarget = GetBrowserParentAncestor(aRemoteTarget);
1930 }
1931}
1932
1933void EventStateManager::DispatchCrossProcessEvent(WidgetEvent* aEvent,
1934 BrowserParent* aRemoteTarget,
1935 nsEventStatus* aStatus) {
1936 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1936); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 1936; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1937 MOZ_ASSERT(aRemoteTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRemoteTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aRemoteTarget))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aRemoteTarget",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1937); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRemoteTarget"
")"); do { *((volatile int*)__null) = 1937; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1938 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1938); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 1938; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1939
1940 BrowserParent* remote = aRemoteTarget;
1941
1942 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
1943 bool isContextMenuKey = mouseEvent && mouseEvent->IsContextMenuKeyEvent();
1944 if (aEvent->mClass == eKeyboardEventClass || isContextMenuKey) {
1945 // APZ attaches a LayersId to hit-testable events, for keyboard events,
1946 // we use focus.
1947 BrowserParent* preciseRemote = BrowserParent::GetFocused();
1948 if (preciseRemote) {
1949 remote = preciseRemote;
1950 }
1951 // else there is a race between layout and focus tracking,
1952 // so fall back to delivering the event to the topmost child process.
1953 } else if (aEvent->mLayersId.IsValid()) {
1954 BrowserParent* preciseRemote =
1955 BrowserParent::GetBrowserParentFromLayersId(aEvent->mLayersId);
1956 if (preciseRemote) {
1957 remote = preciseRemote;
1958 }
1959 // else there is a race between APZ and the LayersId to BrowserParent
1960 // mapping, so fall back to delivering the event to the topmost child
1961 // process.
1962 }
1963
1964 MOZ_ASSERT(aEvent->mMessage != ePointerClick)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage != ePointerClick)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage != ePointerClick
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aEvent->mMessage != ePointerClick", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1964); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage != ePointerClick"
")"); do { *((volatile int*)__null) = 1964; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1965 MOZ_ASSERT(aEvent->mMessage != ePointerAuxClick)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage != ePointerAuxClick)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage != ePointerAuxClick))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage != ePointerAuxClick"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1965); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage != ePointerAuxClick"
")"); do { *((volatile int*)__null) = 1965; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1966
1967 // SendReal* will transform the coordinate to the child process coordinate
1968 // space. So restore the coordinate after the event has been dispatched to the
1969 // child process to avoid using the transformed coordinate afterward.
1970 AutoRestore<LayoutDeviceIntPoint> restore(aEvent->mRefPoint);
1971 switch (aEvent->mClass) {
1972 case ePointerEventClass:
1973 MOZ_ASSERT(aEvent->mMessage == eContextMenu)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eContextMenu)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eContextMenu
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aEvent->mMessage == eContextMenu", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1973); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eContextMenu"
")"); do { *((volatile int*)__null) = 1973; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1974 [[fallthrough]];
1975 case eMouseEventClass: {
1976 BrowserParent* oldRemote = BrowserParent::GetLastMouseRemoteTarget();
1977
1978 // If this is a eMouseExitFromWidget event, need to redirect the event to
1979 // the last remote and and notify all its ancestors about the exit, if
1980 // any.
1981 if (mouseEvent->mMessage == eMouseExitFromWidget) {
1982 MOZ_ASSERT(mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mouseEvent->mExitFrom.value() == WidgetMouseEvent
::ePuppet)>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(mouseEvent->mExitFrom.value() ==
WidgetMouseEvent::ePuppet))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1982); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
")"); do { *((volatile int*)__null) = 1982; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1983 MOZ_ASSERT(mouseEvent->mReason == WidgetMouseEvent::eReal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mouseEvent->mReason == WidgetMouseEvent::eReal)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mouseEvent->mReason == WidgetMouseEvent::eReal)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("mouseEvent->mReason == WidgetMouseEvent::eReal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1983); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mReason == WidgetMouseEvent::eReal"
")"); do { *((volatile int*)__null) = 1983; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1984 MOZ_ASSERT(!mouseEvent->mLayersId.IsValid())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mouseEvent->mLayersId.IsValid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mouseEvent->mLayersId.IsValid
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mouseEvent->mLayersId.IsValid()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1984); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mouseEvent->mLayersId.IsValid()"
")"); do { *((volatile int*)__null) = 1984; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1985 MOZ_ASSERT(remote->GetBrowserHost())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(remote->GetBrowserHost())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(remote->GetBrowserHost())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("remote->GetBrowserHost()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1985); AnnotateMozCrashReason("MOZ_ASSERT" "(" "remote->GetBrowserHost()"
")"); do { *((volatile int*)__null) = 1985; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1986
1987 if (oldRemote && oldRemote != remote) {
1988 Unused << NS_WARN_IF(nsContentUtils::GetCommonBrowserParentAncestor(NS_warn_if_impl(nsContentUtils::GetCommonBrowserParentAncestor
( remote, oldRemote) != remote, "nsContentUtils::GetCommonBrowserParentAncestor( remote, oldRemote) != remote"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1989)
1989 remote, oldRemote) != remote)NS_warn_if_impl(nsContentUtils::GetCommonBrowserParentAncestor
( remote, oldRemote) != remote, "nsContentUtils::GetCommonBrowserParentAncestor( remote, oldRemote) != remote"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1989)
;
1990 remote = oldRemote;
1991 }
1992
1993 DispatchCrossProcessMouseExitEvents(mouseEvent, remote, nullptr, true);
1994 return;
1995 }
1996
1997 if (BrowserParent* pointerLockedRemote =
1998 PointerLockManager::GetLockedRemoteTarget()) {
1999 remote = pointerLockedRemote;
2000 } else if (BrowserParent* pointerCapturedRemote =
2001 PointerEventHandler::GetPointerCapturingRemoteTarget(
2002 mouseEvent->pointerId)) {
2003 remote = pointerCapturedRemote;
2004 } else if (BrowserParent* capturingRemote =
2005 PresShell::GetCapturingRemoteTarget()) {
2006 remote = capturingRemote;
2007 }
2008
2009 // If a mouse is over a remote target A, and then moves to
2010 // remote target B, we'd deliver the event directly to remote target B
2011 // after the moving, A would never get notified that the mouse left.
2012 // So we generate a exit event to notify A after the move.
2013 // XXXedgar, if the synthesized mouse events could deliver to the correct
2014 // process directly (see
2015 // https://bugzilla.mozilla.org/show_bug.cgi?id=1549355), we probably
2016 // don't need to check mReason then.
2017 if (mouseEvent->mReason == WidgetMouseEvent::eReal &&
2018 remote != oldRemote) {
2019 MOZ_ASSERT(mouseEvent->mMessage != eMouseExitFromWidget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mouseEvent->mMessage != eMouseExitFromWidget)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mouseEvent->mMessage != eMouseExitFromWidget))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mouseEvent->mMessage != eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2019); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mMessage != eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 2019; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2020 if (oldRemote) {
2021 BrowserParent* commonAncestor =
2022 nsContentUtils::GetCommonBrowserParentAncestor(remote, oldRemote);
2023 if (commonAncestor == oldRemote) {
2024 // Mouse moves to the inner OOP frame, it is not a really exit.
2025 DispatchCrossProcessMouseExitEvents(
2026 mouseEvent, GetBrowserParentAncestor(remote),
2027 GetBrowserParentAncestor(commonAncestor), false);
2028 } else if (commonAncestor == remote) {
2029 // Mouse moves to the outer OOP frame, it is a really exit.
2030 DispatchCrossProcessMouseExitEvents(mouseEvent, oldRemote,
2031 commonAncestor, true);
2032 } else {
2033 // Mouse moves to OOP frame in other subtree, it is a really exit,
2034 // need to notify all its ancestors before common ancestor about the
2035 // exit.
2036 DispatchCrossProcessMouseExitEvents(mouseEvent, oldRemote,
2037 commonAncestor, true);
2038 if (commonAncestor) {
2039 UniquePtr<WidgetMouseEvent> mouseExitEvent =
2040 CreateMouseOrPointerWidgetEvent(mouseEvent,
2041 eMouseExitFromWidget,
2042 mouseEvent->mRelatedTarget);
2043 mouseExitEvent->mExitFrom =
2044 Some(WidgetMouseEvent::ePuppetParentToPuppetChild);
2045 commonAncestor->SendRealMouseEvent(*mouseExitEvent);
2046 }
2047 }
2048 }
2049
2050 if (mouseEvent->mMessage != eMouseExitFromWidget &&
2051 mouseEvent->mMessage != eMouseEnterIntoWidget) {
2052 // This is to make cursor would be updated correctly.
2053 remote->MouseEnterIntoWidget();
2054 }
2055 }
2056
2057 remote->SendRealMouseEvent(*mouseEvent);
2058 return;
2059 }
2060 case eKeyboardEventClass: {
2061 auto* keyboardEvent = aEvent->AsKeyboardEvent();
2062 if (aEvent->mMessage == eKeyUp) {
2063 HandleKeyUpInteraction(keyboardEvent);
2064 }
2065 remote->SendRealKeyEvent(*keyboardEvent);
2066 return;
2067 }
2068 case eWheelEventClass: {
2069 if (BrowserParent* pointerLockedRemote =
2070 PointerLockManager::GetLockedRemoteTarget()) {
2071 remote = pointerLockedRemote;
2072 }
2073 remote->SendMouseWheelEvent(*aEvent->AsWheelEvent());
2074 return;
2075 }
2076 case eTouchEventClass: {
2077 // Let the child process synthesize a mouse event if needed, and
2078 // ensure we don't synthesize one in this process.
2079 *aStatus = nsEventStatus_eConsumeNoDefault;
2080 remote->SendRealTouchEvent(*aEvent->AsTouchEvent());
2081 return;
2082 }
2083 case eDragEventClass: {
2084 RefPtr<BrowserParent> browserParent = remote;
2085 browserParent->MaybeInvokeDragSession(aEvent->mMessage);
2086
2087 RefPtr<nsIWidget> widget = browserParent->GetTopLevelWidget();
2088 nsCOMPtr<nsIDragSession> dragSession =
2089 nsContentUtils::GetDragSession(widget);
2090 uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
2091 uint32_t action = nsIDragService::DRAGDROP_ACTION_NONE;
2092 nsCOMPtr<nsIPrincipal> principal;
2093 nsCOMPtr<nsIContentSecurityPolicy> csp;
2094
2095 if (dragSession) {
2096 dragSession->DragEventDispatchedToChildProcess();
2097 dragSession->GetDragAction(&action);
2098 dragSession->GetTriggeringPrincipal(getter_AddRefs(principal));
2099 dragSession->GetCsp(getter_AddRefs(csp));
2100 RefPtr<DataTransfer> initialDataTransfer =
2101 dragSession->GetDataTransfer();
2102 if (initialDataTransfer) {
2103 dropEffect = initialDataTransfer->DropEffectInt();
2104 }
2105 }
2106
2107 browserParent->SendRealDragEvent(*aEvent->AsDragEvent(), action,
2108 dropEffect, principal, csp);
2109 return;
2110 }
2111 default: {
2112 MOZ_CRASH("Attempt to send non-whitelisted event?")do { do { } while (false); MOZ_ReportCrash("" "Attempt to send non-whitelisted event?"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2112); AnnotateMozCrashReason("MOZ_CRASH(" "Attempt to send non-whitelisted event?"
")"); do { *((volatile int*)__null) = 2112; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2113 }
2114 }
2115}
2116
2117bool EventStateManager::IsRemoteTarget(nsIContent* target) {
2118 return BrowserParent::GetFrom(target) || BrowserBridgeChild::GetFrom(target);
2119}
2120
2121bool EventStateManager::IsTopLevelRemoteTarget(nsIContent* target) {
2122 return !!BrowserParent::GetFrom(target);
2123}
2124
2125bool EventStateManager::HandleCrossProcessEvent(WidgetEvent* aEvent,
2126 nsEventStatus* aStatus) {
2127 if (!aEvent->CanBeSentToRemoteProcess()) {
2128 return false;
2129 }
2130
2131 MOZ_ASSERT(!aEvent->HasBeenPostedToRemoteProcess(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEvent->HasBeenPostedToRemoteProcess())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aEvent->HasBeenPostedToRemoteProcess()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aEvent->HasBeenPostedToRemoteProcess()"
" (" "Why do we need to post same event to remote processes again?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2132); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aEvent->HasBeenPostedToRemoteProcess()"
") (" "Why do we need to post same event to remote processes again?"
")"); do { *((volatile int*)__null) = 2132; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2132 "Why do we need to post same event to remote processes again?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEvent->HasBeenPostedToRemoteProcess())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aEvent->HasBeenPostedToRemoteProcess()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aEvent->HasBeenPostedToRemoteProcess()"
" (" "Why do we need to post same event to remote processes again?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2132); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aEvent->HasBeenPostedToRemoteProcess()"
") (" "Why do we need to post same event to remote processes again?"
")"); do { *((volatile int*)__null) = 2132; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2133
2134 // Collect the remote event targets we're going to forward this
2135 // event to.
2136 //
2137 // NB: the elements of |remoteTargets| must be unique, for correctness.
2138 AutoTArray<RefPtr<BrowserParent>, 1> remoteTargets;
2139 if (aEvent->mClass != eTouchEventClass || aEvent->mMessage == eTouchStart) {
2140 // If this event only has one target, and it's remote, add it to
2141 // the array.
2142 nsIFrame* frame = aEvent->mMessage == eDragExit
2143 ? sLastDragOverFrame.GetFrame()
2144 : GetEventTarget();
2145 nsIContent* target = frame ? frame->GetContent() : nullptr;
2146 if (BrowserParent* remoteTarget = BrowserParent::GetFrom(target)) {
2147 remoteTargets.AppendElement(remoteTarget);
2148 }
2149 } else {
2150 // This is a touch event with possibly multiple touch points.
2151 // Each touch point may have its own target. So iterate through
2152 // all of them and collect the unique set of targets for event
2153 // forwarding.
2154 //
2155 // This loop is similar to the one used in
2156 // PresShell::DispatchTouchEvent().
2157 const WidgetTouchEvent::TouchArray& touches =
2158 aEvent->AsTouchEvent()->mTouches;
2159 for (uint32_t i = 0; i < touches.Length(); ++i) {
2160 Touch* touch = touches[i];
2161 // NB: the |mChanged| check is an optimization, subprocesses can
2162 // compute this for themselves. If the touch hasn't changed, we
2163 // may be able to avoid forwarding the event entirely (which is
2164 // not free).
2165 if (!touch || !touch->mChanged) {
2166 continue;
2167 }
2168 nsCOMPtr<EventTarget> targetPtr = touch->mTarget;
2169 if (!targetPtr) {
2170 continue;
2171 }
2172 nsCOMPtr<nsIContent> target = do_QueryInterface(targetPtr);
2173 BrowserParent* remoteTarget = BrowserParent::GetFrom(target);
2174 if (remoteTarget && !remoteTargets.Contains(remoteTarget)) {
2175 remoteTargets.AppendElement(remoteTarget);
2176 }
2177 }
2178 }
2179
2180 if (remoteTargets.Length() == 0) {
2181 return false;
2182 }
2183
2184 // Dispatch the event to the remote target.
2185 for (uint32_t i = 0; i < remoteTargets.Length(); ++i) {
2186 DispatchCrossProcessEvent(aEvent, remoteTargets[i], aStatus);
2187 }
2188 return aEvent->HasBeenPostedToRemoteProcess();
2189}
2190
2191//
2192// CreateClickHoldTimer
2193//
2194// Fire off a timer for determining if the user wants click-hold. This timer
2195// is a one-shot that will be cancelled when the user moves enough to fire
2196// a drag.
2197//
2198void EventStateManager::CreateClickHoldTimer(nsPresContext* inPresContext,
2199 nsIFrame* inDownFrame,
2200 WidgetGUIEvent* inMouseDownEvent) {
2201 if (!inMouseDownEvent->IsTrusted() ||
2202 IsTopLevelRemoteTarget(mGestureDownContent) ||
2203 PointerLockManager::IsLocked()) {
2204 return;
2205 }
2206
2207 // just to be anal (er, safe)
2208 if (mClickHoldTimer) {
2209 mClickHoldTimer->Cancel();
2210 mClickHoldTimer = nullptr;
2211 }
2212
2213 // if content clicked on has a popup, don't even start the timer
2214 // since we'll end up conflicting and both will show.
2215 if (mGestureDownContent &&
2216 nsContentUtils::HasNonEmptyAttr(mGestureDownContent, kNameSpaceID_None,
2217 nsGkAtoms::popup)) {
2218 return;
2219 }
2220
2221 int32_t clickHoldDelay = StaticPrefs::ui_click_hold_context_menus_delay();
2222 NS_NewTimerWithFuncCallback(
2223 getter_AddRefs(mClickHoldTimer), sClickHoldCallback, this, clickHoldDelay,
2224 nsITimer::TYPE_ONE_SHOT, "EventStateManager::CreateClickHoldTimer");
2225} // CreateClickHoldTimer
2226
2227//
2228// KillClickHoldTimer
2229//
2230// Stop the timer that would show the context menu dead in its tracks
2231//
2232void EventStateManager::KillClickHoldTimer() {
2233 if (mClickHoldTimer) {
2234 mClickHoldTimer->Cancel();
2235 mClickHoldTimer = nullptr;
2236 }
2237}
2238
2239//
2240// sClickHoldCallback
2241//
2242// This fires after the mouse has been down for a certain length of time.
2243//
2244void EventStateManager::sClickHoldCallback(nsITimer* aTimer, void* aESM) {
2245 RefPtr<EventStateManager> self = static_cast<EventStateManager*>(aESM);
2246 if (self) {
2247 self->FireContextClick();
2248 }
2249
2250 // NOTE: |aTimer| and |self->mAutoHideTimer| are invalid after calling
2251 // ClosePopup();
2252
2253} // sAutoHideCallback
2254
2255//
2256// FireContextClick
2257//
2258// If we're this far, our timer has fired, which means the mouse has been down
2259// for a certain period of time and has not moved enough to generate a
2260// dragGesture. We can be certain the user wants a context-click at this stage,
2261// so generate a dom event and fire it in.
2262//
2263// After the event fires, check if PreventDefault() has been set on the event
2264// which means that someone either ate the event or put up a context menu. This
2265// is our cue to stop tracking the drag gesture. If we always did this,
2266// draggable items w/out a context menu wouldn't be draggable after a certain
2267// length of time, which is _not_ what we want.
2268//
2269void EventStateManager::FireContextClick() {
2270 if (!mGestureDownContent || !mPresContext || PointerLockManager::IsLocked()) {
2271 return;
2272 }
2273
2274#ifdef XP_MACOSX
2275 // Hack to ensure that we don't show a context menu when the user
2276 // let go of the mouse after a long cpu-hogging operation prevented
2277 // us from handling any OS events. See bug 117589.
2278 if (!CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState,
2279 kCGMouseButtonLeft))
2280 return;
2281#endif
2282
2283 nsEventStatus status = nsEventStatus_eIgnore;
2284
2285 // Dispatch to the DOM. We have to fake out the ESM and tell it that the
2286 // current target frame is actually where the mouseDown occurred, otherwise it
2287 // will use the frame the mouse is currently over which may or may not be
2288 // the same. (Note: saari and I have decided that we don't have to reset
2289 // |mCurrentTarget| when we're through because no one else is doing anything
2290 // more with this event and it will get reset on the very next event to the
2291 // correct frame).
2292 mCurrentTarget = mPresContext->GetPrimaryFrameFor(mGestureDownContent);
2293 // make sure the widget sticks around
2294 nsCOMPtr<nsIWidget> targetWidget;
2295 if (mCurrentTarget && (targetWidget = mCurrentTarget->GetNearestWidget())) {
2296 NS_ASSERTION(do { if (!(mPresContext == mCurrentTarget->PresContext()))
{ NS_DebugBreak(NS_DEBUG_ASSERTION, "a prescontext returned a primary frame that didn't belong to it?"
, "mPresContext == mCurrentTarget->PresContext()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2298); MOZ_PretendNoReturn(); } } while (0)
2297 mPresContext == mCurrentTarget->PresContext(),do { if (!(mPresContext == mCurrentTarget->PresContext()))
{ NS_DebugBreak(NS_DEBUG_ASSERTION, "a prescontext returned a primary frame that didn't belong to it?"
, "mPresContext == mCurrentTarget->PresContext()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2298); MOZ_PretendNoReturn(); } } while (0)
2298 "a prescontext returned a primary frame that didn't belong to it?")do { if (!(mPresContext == mCurrentTarget->PresContext()))
{ NS_DebugBreak(NS_DEBUG_ASSERTION, "a prescontext returned a primary frame that didn't belong to it?"
, "mPresContext == mCurrentTarget->PresContext()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2298); MOZ_PretendNoReturn(); } } while (0)
;
2299
2300 // before dispatching, check that we're not on something that
2301 // doesn't get a context menu
2302 bool allowedToDispatch = true;
2303
2304 if (mGestureDownContent->IsAnyOfXULElements(nsGkAtoms::scrollbar,
2305 nsGkAtoms::scrollbarbutton,
2306 nsGkAtoms::button)) {
2307 allowedToDispatch = false;
2308 } else if (mGestureDownContent->IsXULElement(nsGkAtoms::toolbarbutton)) {
2309 // a <toolbarbutton> that has the container attribute set
2310 // will already have its own dropdown.
2311 if (nsContentUtils::HasNonEmptyAttr(
2312 mGestureDownContent, kNameSpaceID_None, nsGkAtoms::container)) {
2313 allowedToDispatch = false;
2314 } else {
2315 // If the toolbar button has an open menu, don't attempt to open
2316 // a second menu
2317 if (mGestureDownContent->IsElement() &&
2318 mGestureDownContent->AsElement()->AttrValueIs(
2319 kNameSpaceID_None, nsGkAtoms::open, nsGkAtoms::_true,
2320 eCaseMatters)) {
2321 allowedToDispatch = false;
2322 }
2323 }
2324 } else if (mGestureDownContent->IsHTMLElement()) {
2325 if (const auto* formCtrl =
2326 nsIFormControl::FromNode(mGestureDownContent)) {
2327 allowedToDispatch =
2328 formCtrl->IsTextControl(/*aExcludePassword*/ false) ||
2329 formCtrl->ControlType() == FormControlType::InputFile;
2330 } else if (mGestureDownContent->IsAnyOfHTMLElements(
2331 nsGkAtoms::embed, nsGkAtoms::object, nsGkAtoms::label)) {
2332 allowedToDispatch = false;
2333 }
2334 }
2335
2336 if (allowedToDispatch) {
2337 // init the event while mCurrentTarget is still good
2338 WidgetPointerEvent event(true, eContextMenu, targetWidget);
2339 event.mClickCount = 1;
2340 FillInEventFromGestureDown(&event);
2341
2342 // we need to forget the clicking content and click count for the
2343 // following eMouseUp event when click-holding context menus
2344 LastMouseDownInfo& mouseDownInfo = GetLastMouseDownInfo(event.mButton);
2345 mouseDownInfo.mLastMouseDownContent = nullptr;
2346 mouseDownInfo.mClickCount = 0;
2347 mouseDownInfo.mLastMouseDownInputControlType = Nothing();
2348
2349 // stop selection tracking, we're in control now
2350 if (mCurrentTarget) {
2351 RefPtr<nsFrameSelection> frameSel = mCurrentTarget->GetFrameSelection();
2352
2353 if (frameSel && frameSel->GetDragState()) {
2354 // note that this can cause selection changed events to fire if we're
2355 // in a text field, which will null out mCurrentTarget
2356 frameSel->SetDragState(false);
2357 }
2358 }
2359
2360 AutoHandlingUserInputStatePusher userInpStatePusher(true, &event);
2361
2362 // dispatch to DOM
2363 RefPtr<nsPresContext> presContext = mPresContext;
2364
2365 // The contextmenu event handled by PresShell will apply to elements (not
2366 // all nodes) correctly and will be dispatched to EventStateManager for
2367 // further handling preventing click event and stopping tracking drag
2368 // gesture.
2369 if (RefPtr<PresShell> presShell = presContext->GetPresShell()) {
2370 presShell->HandleEvent(mCurrentTarget, &event, false, &status);
2371 }
2372
2373 // We don't need to dispatch to frame handling because no frames
2374 // watch eContextMenu except for nsMenuFrame and that's only for
2375 // dismissal. That's just as well since we don't really know
2376 // which frame to send it to.
2377 }
2378 }
2379
2380 // stop tracking a drag whatever the event has been handled or not.
2381 StopTrackingDragGesture(true);
2382
2383 KillClickHoldTimer();
2384
2385} // FireContextClick
2386
2387//
2388// BeginTrackingDragGesture
2389//
2390// Record that the mouse has gone down and that we should move to TRACKING state
2391// of d&d gesture tracker.
2392//
2393// We also use this to track click-hold context menus. When the mouse goes down,
2394// fire off a short timer. If the timer goes off and we have yet to fire the
2395// drag gesture (ie, the mouse hasn't moved a certain distance), then we can
2396// assume the user wants a click-hold, so fire a context-click event. We only
2397// want to cancel the drag gesture if the context-click event is handled.
2398//
2399void EventStateManager::BeginTrackingDragGesture(nsPresContext* aPresContext,
2400 WidgetMouseEvent* inDownEvent,
2401 nsIFrame* inDownFrame) {
2402 if (!inDownEvent->mWidget) {
2403 return;
2404 }
2405
2406 // Note that |inDownEvent| could be either a mouse down event or a
2407 // synthesized mouse move event.
2408 SetGestureDownPoint(inDownEvent);
2409
2410 if (inDownFrame) {
2411 inDownFrame->GetContentForEvent(inDownEvent,
2412 getter_AddRefs(mGestureDownContent));
2413
2414 mGestureDownFrameOwner = inDownFrame->GetContent();
2415 if (!mGestureDownFrameOwner) {
2416 mGestureDownFrameOwner = mGestureDownContent;
2417 }
2418 }
2419 mGestureModifiers = inDownEvent->mModifiers;
2420 mGestureDownButtons = inDownEvent->mButtons;
2421 mGestureDownButton = inDownEvent->mButton;
2422
2423 if (inDownEvent->mMessage != eMouseTouchDrag &&
2424 StaticPrefs::ui_click_hold_context_menus()) {
2425 // fire off a timer to track click-hold
2426 CreateClickHoldTimer(aPresContext, inDownFrame, inDownEvent);
2427 }
2428}
2429
2430void EventStateManager::SetGestureDownPoint(WidgetGUIEvent* aEvent) {
2431 mGestureDownPoint =
2432 GetEventRefPoint(aEvent) + aEvent->mWidget->WidgetToScreenOffset();
2433}
2434
2435LayoutDeviceIntPoint EventStateManager::GetEventRefPoint(
2436 WidgetEvent* aEvent) const {
2437 auto touchEvent = aEvent->AsTouchEvent();
2438 return (touchEvent && !touchEvent->mTouches.IsEmpty())
2439 ? aEvent->AsTouchEvent()->mTouches[0]->mRefPoint
2440 : aEvent->mRefPoint;
2441}
2442
2443void EventStateManager::BeginTrackingRemoteDragGesture(
2444 nsIContent* aContent, RemoteDragStartData* aDragStartData) {
2445 mGestureDownContent = aContent;
2446 mGestureDownFrameOwner = aContent;
2447 mGestureDownInTextControl =
2448 aContent && aContent->IsInNativeAnonymousSubtree() &&
2449 TextControlElement::FromNodeOrNull(
2450 aContent->GetClosestNativeAnonymousSubtreeRootParentOrHost());
2451 mGestureDownDragStartData = aDragStartData;
2452}
2453
2454//
2455// StopTrackingDragGesture
2456//
2457// Record that the mouse has gone back up so that we should leave the TRACKING
2458// state of d&d gesture tracker and return to the START state.
2459//
2460void EventStateManager::StopTrackingDragGesture(bool aClearInChildProcesses) {
2461 mGestureDownContent = nullptr;
2462 mGestureDownFrameOwner = nullptr;
2463 mGestureDownInTextControl = false;
2464 mGestureDownDragStartData = nullptr;
2465
2466 // If a content process starts a drag but the mouse is released before the
2467 // parent starts the actual drag, the content process will think a drag is
2468 // still happening. Inform any child processes with active drags that the drag
2469 // should be stopped.
2470 if (!aClearInChildProcesses || !XRE_IsParentProcess()) {
2471 return;
2472 }
2473
2474 // Only notify if there is NOT a drag session active in the parent.
2475 RefPtr<nsIDragSession> dragSession =
2476 nsContentUtils::GetDragSession(mPresContext);
2477 if (dragSession) {
2478 return;
2479 }
2480 nsCOMPtr<nsIDragService> dragService =
2481 do_GetService("@mozilla.org/widget/dragservice;1");
2482 if (!dragService) {
2483 return;
2484 }
2485 dragService->RemoveAllBrowsers();
2486}
2487
2488void EventStateManager::FillInEventFromGestureDown(WidgetMouseEvent* aEvent) {
2489 NS_ASSERTION(aEvent->mWidget == mCurrentTarget->GetNearestWidget(),do { if (!(aEvent->mWidget == mCurrentTarget->GetNearestWidget
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Incorrect widget in event"
, "aEvent->mWidget == mCurrentTarget->GetNearestWidget()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2490); MOZ_PretendNoReturn(); } } while (0)
2490 "Incorrect widget in event")do { if (!(aEvent->mWidget == mCurrentTarget->GetNearestWidget
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Incorrect widget in event"
, "aEvent->mWidget == mCurrentTarget->GetNearestWidget()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2490); MOZ_PretendNoReturn(); } } while (0)
;
2491
2492 // Set the coordinates in the new event to the coordinates of
2493 // the old event, adjusted for the fact that the widget might be
2494 // different
2495 aEvent->mRefPoint =
2496 mGestureDownPoint - aEvent->mWidget->WidgetToScreenOffset();
2497 aEvent->mModifiers = mGestureModifiers;
2498 aEvent->mButtons = mGestureDownButtons;
2499 if (aEvent->mMessage == eContextMenu) {
2500 aEvent->mButton = mGestureDownButton;
2501 }
2502}
2503
2504void EventStateManager::MaybeFirePointerCancel(WidgetInputEvent* aEvent) {
2505 RefPtr<PresShell> presShell = mPresContext->GetPresShell();
2506 AutoWeakFrame targetFrame = mCurrentTarget;
2507
2508 if (!presShell || !targetFrame) {
2509 return;
2510 }
2511
2512 nsCOMPtr<nsIContent> content;
2513 targetFrame->GetContentForEvent(aEvent, getter_AddRefs(content));
2514 if (!content) {
2515 return;
2516 }
2517
2518 nsEventStatus status = nsEventStatus_eIgnore;
2519
2520 if (WidgetMouseEvent* aMouseEvent = aEvent->AsMouseEvent()) {
2521 WidgetPointerEvent event(*aMouseEvent);
2522 PointerEventHandler::InitPointerEventFromMouse(&event, aMouseEvent,
2523 ePointerCancel);
2524
2525 event.convertToPointer = false;
2526 presShell->HandleEventWithTarget(&event, targetFrame, content, &status);
2527 } else if (WidgetTouchEvent* aTouchEvent = aEvent->AsTouchEvent()) {
2528 WidgetPointerEvent event(aTouchEvent->IsTrusted(), ePointerCancel,
2529 aTouchEvent->mWidget);
2530
2531 PointerEventHandler::InitPointerEventFromTouch(event, *aTouchEvent,
2532 *aTouchEvent->mTouches[0]);
2533
2534 event.convertToPointer = false;
2535 presShell->HandleEventWithTarget(&event, targetFrame, content, &status);
2536 } else {
2537 MOZ_ASSERT(false)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2537); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ")")
; do { *((volatile int*)__null) = 2537; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2538 }
2539
2540 // HandleEventWithTarget clears out mCurrentTarget, which may be used in the
2541 // caller GenerateDragGesture. We have to restore mCurrentTarget.
2542 mCurrentTarget = targetFrame;
2543}
2544
2545bool EventStateManager::IsEventOutsideDragThreshold(
2546 WidgetInputEvent* aEvent) const {
2547 static int32_t sPixelThresholdX = 0;
2548 static int32_t sPixelThresholdY = 0;
2549
2550 if (!sPixelThresholdX) {
2551 sPixelThresholdX =
2552 LookAndFeel::GetInt(LookAndFeel::IntID::DragThresholdX, 0);
2553 sPixelThresholdY =
2554 LookAndFeel::GetInt(LookAndFeel::IntID::DragThresholdY, 0);
2555 if (sPixelThresholdX <= 0) {
2556 sPixelThresholdX = 5;
2557 }
2558 if (sPixelThresholdY <= 0) {
2559 sPixelThresholdY = 5;
2560 }
2561 }
2562
2563 LayoutDeviceIntPoint pt =
2564 aEvent->mWidget->WidgetToScreenOffset() + GetEventRefPoint(aEvent);
2565 LayoutDeviceIntPoint distance = pt - mGestureDownPoint;
2566 return Abs(distance.x) > sPixelThresholdX ||
2567 Abs(distance.y) > sPixelThresholdY;
2568}
2569
2570//
2571// GenerateDragGesture
2572//
2573// If we're in the TRACKING state of the d&d gesture tracker, check the current
2574// position of the mouse in relation to the old one. If we've moved a sufficient
2575// amount from the mouse down, then fire off a drag gesture event.
2576void EventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
2577 WidgetInputEvent* aEvent) {
2578 NS_ASSERTION(aPresContext, "This shouldn't happen.")do { if (!(aPresContext)) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"This shouldn't happen.", "aPresContext", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2578); MOZ_PretendNoReturn(); } } while (0)
;
2579 if (!IsTrackingDragGesture()) {
2580 return;
2581 }
2582
2583 AutoWeakFrame targetFrameBefore = mCurrentTarget;
2584 auto autoRestore = MakeScopeExit([&] { mCurrentTarget = targetFrameBefore; });
2585 mCurrentTarget = mGestureDownFrameOwner->GetPrimaryFrame();
2586
2587 if (!mCurrentTarget || !mCurrentTarget->GetNearestWidget()) {
2588 StopTrackingDragGesture(true);
2589 return;
2590 }
2591
2592 // Check if selection is tracking drag gestures, if so
2593 // don't interfere!
2594 if (mCurrentTarget) {
2595 RefPtr<nsFrameSelection> frameSel = mCurrentTarget->GetFrameSelection();
2596 if (frameSel && frameSel->GetDragState()) {
2597 StopTrackingDragGesture(true);
2598 return;
2599 }
2600 }
2601
2602 // If non-native code is capturing the mouse don't start a drag.
2603 if (PresShell::IsMouseCapturePreventingDrag()) {
2604 StopTrackingDragGesture(true);
2605 return;
2606 }
2607
2608 if (!IsEventOutsideDragThreshold(aEvent)) {
2609 // To keep the old behavior, flush layout even if we don't start dnd.
2610 FlushLayout(aPresContext);
2611 return;
2612 }
2613
2614 if (StaticPrefs::ui_click_hold_context_menus()) {
2615 // stop the click-hold before we fire off the drag gesture, in case
2616 // it takes a long time
2617 KillClickHoldTimer();
2618 }
2619
2620 nsCOMPtr<nsIDocShell> docshell = aPresContext->GetDocShell();
2621 if (!docshell) {
2622 return;
2623 }
2624
2625 nsCOMPtr<nsPIDOMWindowOuter> window = docshell->GetWindow();
2626 if (!window) return;
2627
2628 RefPtr<DataTransfer> dataTransfer =
2629 new DataTransfer(window, eDragStart, /* aIsExternal */ false,
2630 /* aClipboardType */ Nothing());
2631 auto protectDataTransfer = MakeScopeExit([&] {
2632 if (dataTransfer) {
2633 dataTransfer->Disconnect();
2634 }
2635 });
2636
2637 RefPtr<Selection> selection;
2638 RefPtr<RemoteDragStartData> remoteDragStartData;
2639 nsCOMPtr<nsIContent> eventContent, targetContent;
2640 nsCOMPtr<nsIPrincipal> principal;
2641 nsCOMPtr<nsIContentSecurityPolicy> csp;
2642 nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
2643 bool allowEmptyDataTransfer = false;
2644 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(eventContent));
2645 if (eventContent) {
2646 // If the content is a text node in a password field, we shouldn't
2647 // allow to drag its raw text. Note that we've supported drag from
2648 // password fields but dragging data was masked text. So, it doesn't
2649 // make sense anyway.
2650 if (eventContent->IsText() && eventContent->HasFlag(NS_MAYBE_MASKED)) {
2651 // However, it makes sense to allow to drag selected password text
2652 // when copying selected password is allowed because users may want
2653 // to use drag and drop rather than copy and paste when web apps
2654 // request to input password twice for conforming new password but
2655 // they used password generator.
2656 TextEditor* textEditor =
2657 nsContentUtils::GetTextEditorFromAnonymousNodeWithoutCreation(
2658 eventContent);
2659 if (!textEditor || !textEditor->IsCopyToClipboardAllowed()) {
2660 StopTrackingDragGesture(true);
2661 return;
2662 }
2663 }
2664 DetermineDragTargetAndDefaultData(
2665 window, eventContent, dataTransfer, &allowEmptyDataTransfer,
2666 getter_AddRefs(selection), getter_AddRefs(remoteDragStartData),
2667 getter_AddRefs(targetContent), getter_AddRefs(principal),
2668 getter_AddRefs(csp), getter_AddRefs(cookieJarSettings));
2669 }
2670
2671 // Stop tracking the drag gesture now. This should stop us from
2672 // reentering GenerateDragGesture inside DOM event processing.
2673 // Pass false to avoid clearing the child process state since a real
2674 // drag should be starting.
2675 StopTrackingDragGesture(false);
2676
2677 if (!targetContent) return;
2678
2679 // Use our targetContent, now that we've determined it, as the
2680 // parent object of the DataTransfer.
2681 nsCOMPtr<nsIContent> parentContent =
2682 targetContent->FindFirstNonChromeOnlyAccessContent();
2683 dataTransfer->SetParentObject(parentContent);
2684
2685 sLastDragOverFrame = nullptr;
2686 nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget();
2687
2688 // get the widget from the target frame
2689 WidgetDragEvent startEvent(aEvent->IsTrusted(), eDragStart, widget);
2690 startEvent.mFlags.mIsSynthesizedForTests =
2691 aEvent->mFlags.mIsSynthesizedForTests;
2692 FillInEventFromGestureDown(&startEvent);
2693
2694 startEvent.mDataTransfer = dataTransfer;
2695 if (aEvent->AsMouseEvent()) {
2696 startEvent.mInputSource = aEvent->AsMouseEvent()->mInputSource;
2697 } else if (aEvent->AsTouchEvent()) {
2698 startEvent.mInputSource = MouseEvent_Binding::MOZ_SOURCE_TOUCH;
2699 } else {
2700 MOZ_ASSERT(false)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2700); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ")")
; do { *((volatile int*)__null) = 2700; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2701 }
2702
2703 // Dispatch to the DOM. By setting mCurrentTarget we are faking
2704 // out the ESM and telling it that the current target frame is
2705 // actually where the mouseDown occurred, otherwise it will use
2706 // the frame the mouse is currently over which may or may not be
2707 // the same.
2708
2709 // Hold onto old target content through the event and reset after.
2710 nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
2711
2712 // Set the current target to the content for the mouse down
2713 mCurrentTargetContent = targetContent;
2714
2715 // Dispatch the dragstart event to the DOM.
2716 nsEventStatus status = nsEventStatus_eIgnore;
2717 EventDispatcher::Dispatch(targetContent, aPresContext, &startEvent, nullptr,
2718 &status);
2719
2720 WidgetDragEvent* event = &startEvent;
2721
2722 nsCOMPtr<nsIObserverService> observerService =
2723 mozilla::services::GetObserverService();
2724 // Emit observer event to allow addons to modify the DataTransfer
2725 // object.
2726 if (observerService) {
2727 observerService->NotifyObservers(dataTransfer, "on-datatransfer-available",
2728 nullptr);
2729 }
2730
2731 if (status != nsEventStatus_eConsumeNoDefault) {
2732 bool dragStarted = DoDefaultDragStart(aPresContext, event, dataTransfer,
2733 allowEmptyDataTransfer, targetContent,
2734 selection, remoteDragStartData,
2735 principal, csp, cookieJarSettings);
2736 if (dragStarted) {
2737 sActiveESM = nullptr;
2738 MaybeFirePointerCancel(aEvent);
2739 aEvent->StopPropagation();
2740 }
2741 }
2742
2743 // Reset mCurretTargetContent to what it was
2744 mCurrentTargetContent = targetBeforeEvent;
2745
2746 // Now flush all pending notifications, for better responsiveness
2747 // while dragging.
2748 FlushLayout(aPresContext);
2749} // GenerateDragGesture
2750
2751void EventStateManager::DetermineDragTargetAndDefaultData(
2752 nsPIDOMWindowOuter* aWindow, nsIContent* aSelectionTarget,
2753 DataTransfer* aDataTransfer, bool* aAllowEmptyDataTransfer,
2754 Selection** aSelection, RemoteDragStartData** aRemoteDragStartData,
2755 nsIContent** aTargetNode, nsIPrincipal** aPrincipal,
2756 nsIContentSecurityPolicy** aCsp,
2757 nsICookieJarSettings** aCookieJarSettings) {
2758 *aTargetNode = nullptr;
2759 *aAllowEmptyDataTransfer = false;
2760 nsCOMPtr<nsIContent> dragDataNode;
2761
2762 nsIContent* editingElement = aSelectionTarget->IsEditable()
2763 ? aSelectionTarget->GetEditingHost()
2764 : nullptr;
2765
2766 // In chrome, only allow dragging inside editable areas.
2767 bool isChromeContext = !aWindow->GetBrowsingContext()->IsContent();
2768 if (isChromeContext && !editingElement) {
2769 if (mGestureDownDragStartData) {
2770 // A child process started a drag so use any data it assigned for the dnd
2771 // session.
2772 mGestureDownDragStartData->AddInitialDnDDataTo(aDataTransfer, aPrincipal,
2773 aCsp, aCookieJarSettings);
2774 mGestureDownDragStartData.forget(aRemoteDragStartData);
2775 *aAllowEmptyDataTransfer = true;
2776 }
2777 } else {
2778 mGestureDownDragStartData = nullptr;
2779
2780 // GetDragData determines if a selection, link or image in the content
2781 // should be dragged, and places the data associated with the drag in the
2782 // data transfer.
2783 // mGestureDownContent is the node where the mousedown event for the drag
2784 // occurred, and aSelectionTarget is the node to use when a selection is
2785 // used
2786 bool canDrag;
2787 bool wasAlt = (mGestureModifiers & MODIFIER_ALT) != 0;
2788 nsresult rv = nsContentAreaDragDrop::GetDragData(
2789 aWindow, mGestureDownContent, aSelectionTarget, wasAlt, aDataTransfer,
2790 &canDrag, aSelection, getter_AddRefs(dragDataNode), aCsp,
2791 aCookieJarSettings);
2792 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !canDrag) {
2793 return;
2794 }
2795 }
2796
2797 // if GetDragData returned a node, use that as the node being dragged.
2798 // Otherwise, if a selection is being dragged, use the node within the
2799 // selection that was dragged. Otherwise, just use the mousedown target.
2800 nsIContent* dragContent = mGestureDownContent;
2801 if (dragDataNode)
2802 dragContent = dragDataNode;
2803 else if (*aSelection)
2804 dragContent = aSelectionTarget;
2805
2806 nsIContent* originalDragContent = dragContent;
2807
2808 // If a selection isn't being dragged, look for an ancestor with the
2809 // draggable property set. If one is found, use that as the target of the
2810 // drag instead of the node that was clicked on. If a draggable node wasn't
2811 // found, just use the clicked node.
2812 if (!*aSelection) {
2813 while (dragContent) {
2814 if (auto htmlElement = nsGenericHTMLElement::FromNode(dragContent)) {
2815 if (htmlElement->Draggable()) {
2816 // We let draggable elements to trigger dnd even if there is no data
2817 // in the DataTransfer.
2818 *aAllowEmptyDataTransfer = true;
2819 break;
2820 }
2821 } else {
2822 if (dragContent->IsXULElement()) {
2823 // All XUL elements are draggable, so if a XUL element is
2824 // encountered, stop looking for draggable nodes and just use the
2825 // original clicked node instead.
2826 // XXXndeakin
2827 // In the future, we will want to improve this so that XUL has a
2828 // better way to specify whether something is draggable than just
2829 // on/off.
2830 dragContent = mGestureDownContent;
2831 break;
2832 }
2833 // otherwise, it's not an HTML or XUL element, so just keep looking
2834 }
2835 dragContent = dragContent->GetFlattenedTreeParent();
2836 }
2837 }
2838
2839 // if no node in the hierarchy was found to drag, but the GetDragData method
2840 // returned a node, use that returned node. Otherwise, nothing is draggable.
2841 if (!dragContent && dragDataNode) dragContent = dragDataNode;
2842
2843 if (dragContent) {
2844 // if an ancestor node was used instead, clear the drag data
2845 // XXXndeakin rework this a bit. Find a way to just not call GetDragData if
2846 // we don't need to.
2847 if (dragContent != originalDragContent) aDataTransfer->ClearAll();
2848 *aTargetNode = dragContent;
2849 NS_ADDREF(*aTargetNode)(*aTargetNode)->AddRef();
2850 }
2851}
2852
2853bool EventStateManager::DoDefaultDragStart(
2854 nsPresContext* aPresContext, WidgetDragEvent* aDragEvent,
2855 DataTransfer* aDataTransfer, bool aAllowEmptyDataTransfer,
2856 nsIContent* aDragTarget, Selection* aSelection,
2857 RemoteDragStartData* aDragStartData, nsIPrincipal* aPrincipal,
2858 nsIContentSecurityPolicy* aCsp, nsICookieJarSettings* aCookieJarSettings) {
2859 nsCOMPtr<nsIDragService> dragService =
2860 do_GetService("@mozilla.org/widget/dragservice;1");
2861 if (!dragService) return false;
2862
2863 // Default handling for the dragstart event.
2864 //
2865 // First, check if a drag session already exists. This means that the drag
2866 // service was called directly within a draggesture handler. In this case,
2867 // don't do anything more, as it is assumed that the handler is managing
2868 // drag and drop manually. Make sure to return true to indicate that a drag
2869 // began. However, if we're handling drag session for synthesized events,
2870 // we need to initialize some information of the session. Therefore, we
2871 // need to keep going for synthesized case.
2872 if (MOZ_UNLIKELY(!mPresContext)(__builtin_expect(!!(!mPresContext), 0))) {
2873 return true;
2874 }
2875 nsCOMPtr<nsIDragSession> dragSession =
2876 dragService->GetCurrentSession(mPresContext->GetRootWidget());
2877 if (dragSession && !dragSession->IsSynthesizedForTests()) {
2878 return true;
2879 }
2880
2881 // No drag session is currently active, so check if a handler added
2882 // any items to be dragged. If not, there isn't anything to drag.
2883 uint32_t count = 0;
2884 if (aDataTransfer) {
2885 count = aDataTransfer->MozItemCount();
2886 }
2887 if (!aAllowEmptyDataTransfer && !count) {
2888 return false;
2889 }
2890
2891 // Get the target being dragged, which may not be the same as the
2892 // target of the mouse event. If one wasn't set in the
2893 // aDataTransfer during the event handler, just use the original
2894 // target instead.
2895 nsCOMPtr<nsIContent> dragTarget = aDataTransfer->GetDragTarget();
2896 if (!dragTarget) {
2897 dragTarget = aDragTarget;
2898 if (!dragTarget) {
2899 return false;
2900 }
2901 }
2902
2903 // check which drag effect should initially be used. If the effect was not
2904 // set, just use all actions, otherwise Windows won't allow a drop.
2905 uint32_t action = aDataTransfer->EffectAllowedInt();
2906 if (action == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED) {
2907 action = nsIDragService::DRAGDROP_ACTION_COPY |
2908 nsIDragService::DRAGDROP_ACTION_MOVE |
2909 nsIDragService::DRAGDROP_ACTION_LINK;
2910 }
2911
2912 // get any custom drag image that was set
2913 int32_t imageX, imageY;
2914 RefPtr<Element> dragImage = aDataTransfer->GetDragImage(&imageX, &imageY);
2915
2916 nsCOMPtr<nsIArray> transArray = aDataTransfer->GetTransferables(dragTarget);
2917 if (!transArray) {
2918 return false;
2919 }
2920
2921 RefPtr<DataTransfer> dataTransfer;
2922 if (!dragSession) {
2923 // After this function returns, the DataTransfer will be cleared so it
2924 // appears empty to content. We need to pass a DataTransfer into the Drag
2925 // Session, so we need to make a copy.
2926 aDataTransfer->Clone(aDragTarget, eDrop, aDataTransfer->MozUserCancelled(),
2927 false, getter_AddRefs(dataTransfer));
2928
2929 // Copy over the drop effect, as Clone doesn't copy it for us.
2930 dataTransfer->SetDropEffectInt(aDataTransfer->DropEffectInt());
2931 } else {
2932 MOZ_ASSERT(dragSession->IsSynthesizedForTests())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(dragSession->IsSynthesizedForTests())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(dragSession->IsSynthesizedForTests()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("dragSession->IsSynthesizedForTests()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2932); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dragSession->IsSynthesizedForTests()"
")"); do { *((volatile int*)__null) = 2932; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2933 MOZ_ASSERT(aDragEvent->mFlags.mIsSynthesizedForTests)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDragEvent->mFlags.mIsSynthesizedForTests)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aDragEvent->mFlags.mIsSynthesizedForTests))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aDragEvent->mFlags.mIsSynthesizedForTests"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2933); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDragEvent->mFlags.mIsSynthesizedForTests"
")"); do { *((volatile int*)__null) = 2933; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2934 // If we're initializing synthesized drag session, we should use given
2935 // DataTransfer as is because it'll be used with following drag events
2936 // in any tests, therefore it should be set to nsIDragSession.dataTransfer
2937 // because it and DragEvent.dataTransfer should be same instance.
2938 dataTransfer = aDataTransfer;
2939 }
2940
2941 // XXXndeakin don't really want to create a new drag DOM event
2942 // here, but we need something to pass to the InvokeDragSession
2943 // methods.
2944 RefPtr<DragEvent> event =
2945 NS_NewDOMDragEvent(dragTarget, aPresContext, aDragEvent);
2946
2947 // Use InvokeDragSessionWithSelection if a selection is being dragged,
2948 // such that the image can be generated from the selected text. However,
2949 // use InvokeDragSessionWithImage if a custom image was set or something
2950 // other than a selection is being dragged.
2951 if (!dragImage && aSelection) {
2952 dragService->InvokeDragSessionWithSelection(
2953 aSelection, aPrincipal, aCsp, aCookieJarSettings, transArray, action,
2954 event, dataTransfer, dragTarget);
2955 } else if (aDragStartData) {
2956 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2956); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 2956; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2957 dragService->InvokeDragSessionWithRemoteImage(
2958 dragTarget, aPrincipal, aCsp, aCookieJarSettings, transArray, action,
2959 aDragStartData, event, dataTransfer);
2960 } else {
2961 dragService->InvokeDragSessionWithImage(
2962 dragTarget, aPrincipal, aCsp, aCookieJarSettings, transArray, action,
2963 dragImage, imageX, imageY, event, dataTransfer);
2964 }
2965
2966 return true;
2967}
2968
2969void EventStateManager::ChangeZoom(bool aIncrease) {
2970 // Send the zoom change to the top level browser so it will be handled by the
2971 // front end in the same way as other zoom actions.
2972 nsIDocShell* docShell = mDocument->GetDocShell();
2973 if (!docShell) {
2974 return;
2975 }
2976
2977 BrowsingContext* bc = docShell->GetBrowsingContext();
2978 if (!bc) {
2979 return;
2980 }
2981
2982 if (XRE_IsParentProcess()) {
2983 bc->Canonical()->DispatchWheelZoomChange(aIncrease);
2984 } else if (BrowserChild* child = BrowserChild::GetFrom(docShell)) {
2985 child->SendWheelZoomChange(aIncrease);
2986 }
2987}
2988
2989void EventStateManager::DoScrollHistory(int32_t direction) {
2990 nsCOMPtr<nsISupports> pcContainer(mPresContext->GetContainerWeak());
2991 if (pcContainer) {
2992 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(pcContainer));
2993 if (webNav) {
2994 // positive direction to go back one step, nonpositive to go forward
2995 // This is doing user-initiated history traversal, hence we want
2996 // to require that history entries we navigate to have user interaction.
2997 if (direction > 0)
2998 webNav->GoBack(StaticPrefs::browser_navigation_requireUserInteraction(),
2999 true);
3000 else
3001 webNav->GoForward(
3002 StaticPrefs::browser_navigation_requireUserInteraction(), true);
3003 }
3004 }
3005}
3006
3007void EventStateManager::DoScrollZoom(nsIFrame* aTargetFrame,
3008 int32_t adjustment) {
3009 // Exclude content in chrome docshells.
3010 nsIContent* content = aTargetFrame->GetContent();
3011 if (content && !nsContentUtils::IsInChromeDocshell(content->OwnerDoc())) {
3012 // Positive adjustment to decrease zoom, negative to increase
3013 const bool increase = adjustment <= 0;
3014 EnsureDocument(mPresContext);
3015 ChangeZoom(increase);
3016 }
3017}
3018
3019static nsIFrame* GetParentFrameToScroll(nsIFrame* aFrame) {
3020 if (!aFrame) return nullptr;
3021
3022 if (aFrame->StyleDisplay()->mPosition == StylePositionProperty::Fixed &&
3023 nsLayoutUtils::IsReallyFixedPos(aFrame)) {
3024 return aFrame->PresShell()->GetRootScrollContainerFrame();
3025 }
3026 return aFrame->GetParent();
3027}
3028
3029void EventStateManager::DispatchLegacyMouseScrollEvents(
3030 nsIFrame* aTargetFrame, WidgetWheelEvent* aEvent, nsEventStatus* aStatus) {
3031 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3031); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 3031; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3032 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3032); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 3032; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3033
3034 if (!aTargetFrame || *aStatus == nsEventStatus_eConsumeNoDefault) {
3035 return;
3036 }
3037
3038 // Ignore mouse wheel transaction for computing legacy mouse wheel
3039 // events' delta value.
3040 // DOM event's delta vales are computed from CSS pixels.
3041 auto scrollAmountInCSSPixels =
3042 CSSIntSize::FromAppUnitsRounded(aEvent->mScrollAmount);
3043
3044 // XXX We don't deal with fractional amount in legacy event, though the
3045 // default action handler (DoScrollText()) deals with it.
3046 // If we implemented such strict computation, we would need additional
3047 // accumulated delta values. It would made the code more complicated.
3048 // And also it would computes different delta values from older version.
3049 // It doesn't make sense to implement such code for legacy events and
3050 // rare cases.
3051 int32_t scrollDeltaX, scrollDeltaY, pixelDeltaX, pixelDeltaY;
3052 switch (aEvent->mDeltaMode) {
3053 case WheelEvent_Binding::DOM_DELTA_PAGE:
3054 scrollDeltaX = !aEvent->mLineOrPageDeltaX
3055 ? 0
3056 : (aEvent->mLineOrPageDeltaX > 0
3057 ? UIEvent_Binding::SCROLL_PAGE_DOWN
3058 : UIEvent_Binding::SCROLL_PAGE_UP);
3059 scrollDeltaY = !aEvent->mLineOrPageDeltaY
3060 ? 0
3061 : (aEvent->mLineOrPageDeltaY > 0
3062 ? UIEvent_Binding::SCROLL_PAGE_DOWN
3063 : UIEvent_Binding::SCROLL_PAGE_UP);
3064 pixelDeltaX = RoundDown(aEvent->mDeltaX * scrollAmountInCSSPixels.width);
3065 pixelDeltaY = RoundDown(aEvent->mDeltaY * scrollAmountInCSSPixels.height);
3066 break;
3067
3068 case WheelEvent_Binding::DOM_DELTA_LINE:
3069 scrollDeltaX = aEvent->mLineOrPageDeltaX;
3070 scrollDeltaY = aEvent->mLineOrPageDeltaY;
3071 pixelDeltaX = RoundDown(aEvent->mDeltaX * scrollAmountInCSSPixels.width);
3072 pixelDeltaY = RoundDown(aEvent->mDeltaY * scrollAmountInCSSPixels.height);
3073 break;
3074
3075 case WheelEvent_Binding::DOM_DELTA_PIXEL:
3076 scrollDeltaX = aEvent->mLineOrPageDeltaX;
3077 scrollDeltaY = aEvent->mLineOrPageDeltaY;
3078 pixelDeltaX = RoundDown(aEvent->mDeltaX);
3079 pixelDeltaY = RoundDown(aEvent->mDeltaY);
3080 break;
3081
3082 default:
3083 MOZ_CRASH("Invalid deltaMode value comes")do { do { } while (false); MOZ_ReportCrash("" "Invalid deltaMode value comes"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3083); AnnotateMozCrashReason("MOZ_CRASH(" "Invalid deltaMode value comes"
")"); do { *((volatile int*)__null) = 3083; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
3084 }
3085
3086 // Send the legacy events in following order:
3087 // 1. Vertical scroll
3088 // 2. Vertical pixel scroll (even if #1 isn't consumed)
3089 // 3. Horizontal scroll (even if #1 and/or #2 are consumed)
3090 // 4. Horizontal pixel scroll (even if #3 isn't consumed)
3091
3092 AutoWeakFrame targetFrame(aTargetFrame);
3093
3094 MOZ_ASSERT(*aStatus != nsEventStatus_eConsumeNoDefault &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault &&
!aEvent->DefaultPrevented())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aStatus != nsEventStatus_eConsumeNoDefault
&& !aEvent->DefaultPrevented()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
" (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3097); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
") (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")"); do {
*((volatile int*)__null) = 3097; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3095 !aEvent->DefaultPrevented(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault &&
!aEvent->DefaultPrevented())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aStatus != nsEventStatus_eConsumeNoDefault
&& !aEvent->DefaultPrevented()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
" (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3097); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
") (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")"); do {
*((volatile int*)__null) = 3097; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3096 "If you make legacy events dispatched for default prevented wheel "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault &&
!aEvent->DefaultPrevented())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aStatus != nsEventStatus_eConsumeNoDefault
&& !aEvent->DefaultPrevented()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
" (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3097); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
") (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")"); do {
*((volatile int*)__null) = 3097; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3097 "event, you need to initialize stateX and stateY")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault &&
!aEvent->DefaultPrevented())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aStatus != nsEventStatus_eConsumeNoDefault
&& !aEvent->DefaultPrevented()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
" (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3097); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
") (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")"); do {
*((volatile int*)__null) = 3097; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
3098 EventState stateX, stateY;
3099 if (scrollDeltaY) {
3100 SendLineScrollEvent(aTargetFrame, aEvent, stateY, scrollDeltaY,
3101 DELTA_DIRECTION_Y);
3102 if (!targetFrame.IsAlive()) {
3103 *aStatus = nsEventStatus_eConsumeNoDefault;
3104 return;
3105 }
3106 }
3107
3108 if (pixelDeltaY) {
3109 SendPixelScrollEvent(aTargetFrame, aEvent, stateY, pixelDeltaY,
3110 DELTA_DIRECTION_Y);
3111 if (!targetFrame.IsAlive()) {
3112 *aStatus = nsEventStatus_eConsumeNoDefault;
3113 return;
3114 }
3115 }
3116
3117 if (scrollDeltaX) {
3118 SendLineScrollEvent(aTargetFrame, aEvent, stateX, scrollDeltaX,
3119 DELTA_DIRECTION_X);
3120 if (!targetFrame.IsAlive()) {
3121 *aStatus = nsEventStatus_eConsumeNoDefault;
3122 return;
3123 }
3124 }
3125
3126 if (pixelDeltaX) {
3127 SendPixelScrollEvent(aTargetFrame, aEvent, stateX, pixelDeltaX,
3128 DELTA_DIRECTION_X);
3129 if (!targetFrame.IsAlive()) {
3130 *aStatus = nsEventStatus_eConsumeNoDefault;
3131 return;
3132 }
3133 }
3134
3135 if (stateY.mDefaultPrevented) {
3136 *aStatus = nsEventStatus_eConsumeNoDefault;
3137 aEvent->PreventDefault(!stateY.mDefaultPreventedByContent);
3138 }
3139
3140 if (stateX.mDefaultPrevented) {
3141 *aStatus = nsEventStatus_eConsumeNoDefault;
3142 aEvent->PreventDefault(!stateX.mDefaultPreventedByContent);
3143 }
3144}
3145
3146void EventStateManager::SendLineScrollEvent(nsIFrame* aTargetFrame,
3147 WidgetWheelEvent* aEvent,
3148 EventState& aState, int32_t aDelta,
3149 DeltaDirection aDeltaDirection) {
3150 nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
3151 if (!targetContent) {
3152 targetContent = GetFocusedElement();
3153 if (!targetContent) {
3154 return;
3155 }
3156 }
3157
3158 while (targetContent->IsText()) {
3159 targetContent = targetContent->GetFlattenedTreeParent();
3160 }
3161
3162 WidgetMouseScrollEvent event(aEvent->IsTrusted(),
3163 eLegacyMouseLineOrPageScroll, aEvent->mWidget);
3164 event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
3165 event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
3166 event.mRefPoint = aEvent->mRefPoint;
3167 event.mTimeStamp = aEvent->mTimeStamp;
3168 event.mModifiers = aEvent->mModifiers;
3169 event.mButtons = aEvent->mButtons;
3170 event.mIsHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
3171 event.mDelta = aDelta;
3172 event.mInputSource = aEvent->mInputSource;
3173
3174 RefPtr<nsPresContext> presContext = aTargetFrame->PresContext();
3175 nsEventStatus status = nsEventStatus_eIgnore;
3176 EventDispatcher::Dispatch(targetContent, presContext, &event, nullptr,
3177 &status);
3178 aState.mDefaultPrevented =
3179 event.DefaultPrevented() || status == nsEventStatus_eConsumeNoDefault;
3180 aState.mDefaultPreventedByContent = event.DefaultPreventedByContent();
3181}
3182
3183void EventStateManager::SendPixelScrollEvent(nsIFrame* aTargetFrame,
3184 WidgetWheelEvent* aEvent,
3185 EventState& aState,
3186 int32_t aPixelDelta,
3187 DeltaDirection aDeltaDirection) {
3188 nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
3189 if (!targetContent) {
3190 targetContent = GetFocusedElement();
3191 if (!targetContent) {
3192 return;
3193 }
3194 }
3195
3196 while (targetContent->IsText()) {
3197 targetContent = targetContent->GetFlattenedTreeParent();
3198 }
3199
3200 WidgetMouseScrollEvent event(aEvent->IsTrusted(), eLegacyMousePixelScroll,
3201 aEvent->mWidget);
3202 event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
3203 event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
3204 event.mRefPoint = aEvent->mRefPoint;
3205 event.mTimeStamp = aEvent->mTimeStamp;
3206 event.mModifiers = aEvent->mModifiers;
3207 event.mButtons = aEvent->mButtons;
3208 event.mIsHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
3209 event.mDelta = aPixelDelta;
3210 event.mInputSource = aEvent->mInputSource;
3211
3212 RefPtr<nsPresContext> presContext = aTargetFrame->PresContext();
3213 nsEventStatus status = nsEventStatus_eIgnore;
3214 EventDispatcher::Dispatch(targetContent, presContext, &event, nullptr,
3215 &status);
3216 aState.mDefaultPrevented =
3217 event.DefaultPrevented() || status == nsEventStatus_eConsumeNoDefault;
3218 aState.mDefaultPreventedByContent = event.DefaultPreventedByContent();
3219}
3220
3221ScrollContainerFrame*
3222EventStateManager::ComputeScrollTargetAndMayAdjustWheelEvent(
3223 nsIFrame* aTargetFrame, WidgetWheelEvent* aEvent,
3224 ComputeScrollTargetOptions aOptions) {
3225 return ComputeScrollTargetAndMayAdjustWheelEvent(
3226 aTargetFrame, aEvent->mDeltaX, aEvent->mDeltaY, aEvent, aOptions);
3227}
3228
3229// Overload ComputeScrollTargetAndMayAdjustWheelEvent method to allow passing
3230// "test" dx and dy when looking for which scrollbarmediators to activate when
3231// two finger down on trackpad and before any actual motion
3232ScrollContainerFrame*
3233EventStateManager::ComputeScrollTargetAndMayAdjustWheelEvent(
3234 nsIFrame* aTargetFrame, double aDirectionX, double aDirectionY,
3235 WidgetWheelEvent* aEvent, ComputeScrollTargetOptions aOptions) {
3236 bool isAutoDir = false;
3237 bool honoursRoot = false;
3238 if (MAY_BE_ADJUSTED_BY_AUTO_DIR & aOptions) {
3239 // If the scroll is respected as auto-dir, aDirection* should always be
3240 // equivalent to the event's delta vlaues(Currently, there are only one case
3241 // where aDirection*s have different values from the widget wheel event's
3242 // original delta values and the only case isn't auto-dir, see
3243 // ScrollbarsForWheel::TemporarilyActivateAllPossibleScrollTargets).
3244 MOZ_ASSERT(aDirectionX == aEvent->mDeltaX &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDirectionX == aEvent->mDeltaX && aDirectionY
== aEvent->mDeltaY)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDirectionX == aEvent->mDeltaX
&& aDirectionY == aEvent->mDeltaY))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aDirectionX == aEvent->mDeltaX && aDirectionY == aEvent->mDeltaY"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3245); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDirectionX == aEvent->mDeltaX && aDirectionY == aEvent->mDeltaY"
")"); do { *((volatile int*)__null) = 3245; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3245 aDirectionY == aEvent->mDeltaY)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDirectionX == aEvent->mDeltaX && aDirectionY
== aEvent->mDeltaY)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDirectionX == aEvent->mDeltaX
&& aDirectionY == aEvent->mDeltaY))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aDirectionX == aEvent->mDeltaX && aDirectionY == aEvent->mDeltaY"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3245); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDirectionX == aEvent->mDeltaX && aDirectionY == aEvent->mDeltaY"
")"); do { *((volatile int*)__null) = 3245; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3246
3247 WheelDeltaAdjustmentStrategy strategy =
3248 GetWheelDeltaAdjustmentStrategy(*aEvent);
3249 switch (strategy) {
3250 case WheelDeltaAdjustmentStrategy::eAutoDir:
3251 isAutoDir = true;
3252 honoursRoot = false;
3253 break;
3254 case WheelDeltaAdjustmentStrategy::eAutoDirWithRootHonour:
3255 isAutoDir = true;
3256 honoursRoot = true;
3257 break;
3258 default:
3259 break;
3260 }
3261 }
3262
3263 if (aOptions & PREFER_MOUSE_WHEEL_TRANSACTION) {
3264 // If the user recently scrolled with the mousewheel, then they probably
3265 // want to scroll the same view as before instead of the view under the
3266 // cursor. WheelTransaction tracks the frame currently being
3267 // scrolled with the mousewheel. We consider the transaction ended when the
3268 // mouse moves more than "mousewheel.transaction.ignoremovedelay"
3269 // milliseconds after the last scroll operation, or any time the mouse moves
3270 // out of the frame, or when more than "mousewheel.transaction.timeout"
3271 // milliseconds have passed after the last operation, even if the mouse
3272 // hasn't moved.
3273 nsIFrame* lastScrollFrame = WheelTransaction::GetScrollTargetFrame();
3274 if (lastScrollFrame) {
3275 ScrollContainerFrame* scrollContainerFrame =
3276 lastScrollFrame->GetScrollTargetFrame();
3277 if (scrollContainerFrame) {
3278 if (isAutoDir) {
3279 ESMAutoDirWheelDeltaAdjuster adjuster(*aEvent, *lastScrollFrame,
3280 honoursRoot);
3281 // Note that calling this function will not always cause the delta to
3282 // be adjusted, it only adjusts the delta when it should, because
3283 // Adjust() internally calls ShouldBeAdjusted() before making
3284 // adjustment.
3285 adjuster.Adjust();
3286 }
3287 return scrollContainerFrame;
3288 }
3289 }
3290 }
3291
3292 // If the event doesn't cause scroll actually, we cannot find scroll target
3293 // because we check if the event can cause scroll actually on each found
3294 // scrollable frame.
3295 if (!aDirectionX && !aDirectionY) {
3296 return nullptr;
3297 }
3298
3299 bool checkIfScrollableX;
3300 bool checkIfScrollableY;
3301 if (isAutoDir) {
3302 // Always check the frame's scrollability in both the two directions for an
3303 // auto-dir scroll. That is, for an auto-dir scroll,
3304 // PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS and
3305 // PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS should be ignored.
3306 checkIfScrollableX = true;
3307 checkIfScrollableY = true;
3308 } else {
3309 checkIfScrollableX =
3310 aDirectionX &&
3311 (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS);
3312 checkIfScrollableY =
3313 aDirectionY &&
3314 (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS);
3315 }
3316
3317 nsIFrame* scrollFrame = !(aOptions & START_FROM_PARENT)
3318 ? aTargetFrame
3319 : GetParentFrameToScroll(aTargetFrame);
3320 for (; scrollFrame; scrollFrame = GetParentFrameToScroll(scrollFrame)) {
3321 // Check whether the frame wants to provide us with a scrollable view.
3322 ScrollContainerFrame* scrollContainerFrame =
3323 scrollFrame->GetScrollTargetFrame();
3324 if (!scrollContainerFrame) {
3325 nsMenuPopupFrame* menuPopupFrame = do_QueryFrame(scrollFrame);
3326 if (menuPopupFrame) {
3327 return nullptr;
3328 }
3329 continue;
3330 }
3331
3332 if (!checkIfScrollableX && !checkIfScrollableY) {
3333 return scrollContainerFrame;
3334 }
3335
3336 // If the frame disregards the direction the user is trying to scroll, then
3337 // it should just bubbles the scroll event up to its parental scroll frame
3338
3339 Maybe<layers::ScrollDirection> disregardedDirection =
3340 WheelHandlingUtils::GetDisregardedWheelScrollDirection(scrollFrame);
3341 if (disregardedDirection) {
3342 switch (disregardedDirection.ref()) {
3343 case layers::ScrollDirection::eHorizontal:
3344 if (checkIfScrollableX) {
3345 continue;
3346 }
3347 break;
3348 case layers::ScrollDirection::eVertical:
3349 if (checkIfScrollableY) {
3350 continue;
3351 }
3352 break;
3353 }
3354 }
3355
3356 layers::ScrollDirections directions =
3357 scrollContainerFrame
3358 ->GetAvailableScrollingDirectionsForUserInputEvents();
3359 if ((!(directions.contains(layers::ScrollDirection::eVertical)) &&
3360 !(directions.contains(layers::ScrollDirection::eHorizontal))) ||
3361 (checkIfScrollableY && !checkIfScrollableX &&
3362 !(directions.contains(layers::ScrollDirection::eVertical))) ||
3363 (checkIfScrollableX && !checkIfScrollableY &&
3364 !(directions.contains(layers::ScrollDirection::eHorizontal)))) {
3365 continue;
3366 }
3367
3368 // Computes whether the currently checked frame is scrollable by this wheel
3369 // event.
3370 bool canScroll = false;
3371 if (isAutoDir) {
3372 ESMAutoDirWheelDeltaAdjuster adjuster(*aEvent, *scrollFrame, honoursRoot);
3373 if (adjuster.ShouldBeAdjusted()) {
3374 adjuster.Adjust();
3375 canScroll = true;
3376 } else if (WheelHandlingUtils::CanScrollOn(scrollContainerFrame,
3377 aDirectionX, aDirectionY)) {
3378 canScroll = true;
3379 }
3380 } else if (WheelHandlingUtils::CanScrollOn(scrollContainerFrame,
3381 aDirectionX, aDirectionY)) {
3382 canScroll = true;
3383 }
3384
3385 if (canScroll) {
3386 return scrollContainerFrame;
3387 }
3388
3389 // Where we are at is the block ending in a for loop.
3390 // The current frame has been checked to be unscrollable by this wheel
3391 // event, continue the loop to check its parent, if any.
3392 }
3393
3394 nsIFrame* newFrame = nsLayoutUtils::GetCrossDocParentFrameInProcess(
3395 aTargetFrame->PresShell()->GetRootFrame());
3396 aOptions =
3397 static_cast<ComputeScrollTargetOptions>(aOptions & ~START_FROM_PARENT);
3398 if (!newFrame) {
3399 return nullptr;
3400 }
3401 return ComputeScrollTargetAndMayAdjustWheelEvent(newFrame, aEvent, aOptions);
3402}
3403
3404nsSize EventStateManager::GetScrollAmount(
3405 nsPresContext* aPresContext, WidgetWheelEvent* aEvent,
3406 ScrollContainerFrame* aScrollContainerFrame) {
3407 MOZ_ASSERT(aPresContext)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresContext))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPresContext", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3407); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresContext"
")"); do { *((volatile int*)__null) = 3407; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3408 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3408); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 3408; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3409
3410 const bool isPage = aEvent->mDeltaMode == WheelEvent_Binding::DOM_DELTA_PAGE;
3411 if (!aScrollContainerFrame) {
3412 // If there is no scrollable frame, we should use root, see below.
3413 aScrollContainerFrame =
3414 aPresContext->PresShell()->GetRootScrollContainerFrame();
3415 }
3416
3417 if (aScrollContainerFrame) {
3418 return isPage ? aScrollContainerFrame->GetPageScrollAmount()
3419 : aScrollContainerFrame->GetLineScrollAmount();
3420 }
3421
3422 // If there is no scrollable frame and page scrolling, use viewport size.
3423 if (isPage) {
3424 return aPresContext->GetVisibleArea().Size();
3425 }
3426
3427 // Otherwise use root frame's font metrics.
3428 //
3429 // FIXME(emilio): Should this use the root element's style frame? The root
3430 // frame will always have the initial font. Then again it should never matter
3431 // for content, we should always have a root scrollable frame in html
3432 // documents.
3433 nsIFrame* rootFrame = aPresContext->PresShell()->GetRootFrame();
3434 if (!rootFrame) {
3435 return nsSize(0, 0);
3436 }
3437 RefPtr<nsFontMetrics> fm =
3438 nsLayoutUtils::GetInflatedFontMetricsForFrame(rootFrame);
3439 NS_ENSURE_TRUE(fm, nsSize(0, 0))do { if ((__builtin_expect(!!(!(fm)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "fm" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3439); return nsSize(0, 0); } } while (false)
;
3440 return nsSize(fm->AveCharWidth(), fm->MaxHeight());
3441}
3442
3443void EventStateManager::DoScrollText(
3444 ScrollContainerFrame* aScrollContainerFrame, WidgetWheelEvent* aEvent) {
3445 MOZ_ASSERT(aScrollContainerFrame)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aScrollContainerFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aScrollContainerFrame))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aScrollContainerFrame"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3445); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aScrollContainerFrame"
")"); do { *((volatile int*)__null) = 3445; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3446 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3446); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 3446; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3447
3448 AutoWeakFrame scrollFrameWeak(aScrollContainerFrame);
3449 AutoWeakFrame eventFrameWeak(mCurrentTarget);
3450 if (!WheelTransaction::WillHandleDefaultAction(aEvent, scrollFrameWeak,
3451 eventFrameWeak)) {
3452 return;
3453 }
3454
3455 // Default action's actual scroll amount should be computed from device
3456 // pixels.
3457 nsPresContext* pc = aScrollContainerFrame->PresContext();
3458 nsSize scrollAmount = GetScrollAmount(pc, aEvent, aScrollContainerFrame);
3459 nsIntSize scrollAmountInDevPixels(
3460 pc->AppUnitsToDevPixels(scrollAmount.width),
3461 pc->AppUnitsToDevPixels(scrollAmount.height));
3462 nsIntPoint actualDevPixelScrollAmount =
3463 DeltaAccumulator::GetInstance()->ComputeScrollAmountForDefaultAction(
3464 aEvent, scrollAmountInDevPixels);
3465
3466 // Don't scroll around the axis whose overflow style is hidden.
3467 ScrollStyles overflowStyle = aScrollContainerFrame->GetScrollStyles();
3468 if (overflowStyle.mHorizontal == StyleOverflow::Hidden) {
3469 actualDevPixelScrollAmount.x = 0;
3470 }
3471 if (overflowStyle.mVertical == StyleOverflow::Hidden) {
3472 actualDevPixelScrollAmount.y = 0;
3473 }
3474
3475 ScrollSnapFlags snapFlags = ScrollSnapFlags::Disabled;
3476 mozilla::ScrollOrigin origin = mozilla::ScrollOrigin::NotSpecified;
3477 switch (aEvent->mDeltaMode) {
3478 case WheelEvent_Binding::DOM_DELTA_LINE:
3479 origin = mozilla::ScrollOrigin::MouseWheel;
3480 snapFlags = ScrollSnapFlags::IntendedDirection;
3481 break;
3482 case WheelEvent_Binding::DOM_DELTA_PAGE:
3483 origin = mozilla::ScrollOrigin::Pages;
3484 snapFlags = ScrollSnapFlags::IntendedDirection |
3485 ScrollSnapFlags::IntendedEndPosition;
3486 break;
3487 case WheelEvent_Binding::DOM_DELTA_PIXEL:
3488 origin = mozilla::ScrollOrigin::Pixels;
3489 break;
3490 default:
3491 MOZ_CRASH("Invalid deltaMode value comes")do { do { } while (false); MOZ_ReportCrash("" "Invalid deltaMode value comes"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3491); AnnotateMozCrashReason("MOZ_CRASH(" "Invalid deltaMode value comes"
")"); do { *((volatile int*)__null) = 3491; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
3492 }
3493
3494 // We shouldn't scroll more one page at once except when over one page scroll
3495 // is allowed for the event.
3496 nsSize pageSize = aScrollContainerFrame->GetPageScrollAmount();
3497 nsIntSize devPixelPageSize(pc->AppUnitsToDevPixels(pageSize.width),
3498 pc->AppUnitsToDevPixels(pageSize.height));
3499 if (!WheelPrefs::GetInstance()->IsOverOnePageScrollAllowedX(aEvent) &&
3500 DeprecatedAbs(actualDevPixelScrollAmount.x.value) >
3501 devPixelPageSize.width) {
3502 actualDevPixelScrollAmount.x = (actualDevPixelScrollAmount.x >= 0)
3503 ? devPixelPageSize.width
3504 : -devPixelPageSize.width;
3505 }
3506
3507 if (!WheelPrefs::GetInstance()->IsOverOnePageScrollAllowedY(aEvent) &&
3508 DeprecatedAbs(actualDevPixelScrollAmount.y.value) >
3509 devPixelPageSize.height) {
3510 actualDevPixelScrollAmount.y = (actualDevPixelScrollAmount.y >= 0)
3511 ? devPixelPageSize.height
3512 : -devPixelPageSize.height;
3513 }
3514
3515 bool isDeltaModePixel =
3516 (aEvent->mDeltaMode == WheelEvent_Binding::DOM_DELTA_PIXEL);
3517
3518 ScrollMode mode;
3519 switch (aEvent->mScrollType) {
3520 case WidgetWheelEvent::SCROLL_DEFAULT:
3521 if (isDeltaModePixel) {
3522 mode = ScrollMode::Normal;
3523 } else if (aEvent->mFlags.mHandledByAPZ) {
3524 mode = ScrollMode::SmoothMsd;
3525 } else {
3526 mode = ScrollMode::Smooth;
3527 }
3528 break;
3529 case WidgetWheelEvent::SCROLL_SYNCHRONOUSLY:
3530 mode = ScrollMode::Instant;
3531 break;
3532 case WidgetWheelEvent::SCROLL_ASYNCHRONOUSLY:
3533 mode = ScrollMode::Normal;
3534 break;
3535 case WidgetWheelEvent::SCROLL_SMOOTHLY:
3536 mode = ScrollMode::Smooth;
3537 break;
3538 default:
3539 MOZ_CRASH("Invalid mScrollType value comes")do { do { } while (false); MOZ_ReportCrash("" "Invalid mScrollType value comes"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3539); AnnotateMozCrashReason("MOZ_CRASH(" "Invalid mScrollType value comes"
")"); do { *((volatile int*)__null) = 3539; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
3540 }
3541
3542 ScrollContainerFrame::ScrollMomentum momentum =
3543 aEvent->mIsMomentum ? ScrollContainerFrame::SYNTHESIZED_MOMENTUM_EVENT
3544 : ScrollContainerFrame::NOT_MOMENTUM;
3545
3546 nsIntPoint overflow;
3547 aScrollContainerFrame->ScrollBy(actualDevPixelScrollAmount,
3548 ScrollUnit::DEVICE_PIXELS, mode, &overflow,
3549 origin, momentum, snapFlags);
3550
3551 if (!scrollFrameWeak.IsAlive()) {
3552 // If the scroll causes changing the layout, we can think that the event
3553 // has been completely consumed by the content. Then, users probably don't
3554 // want additional action.
3555 aEvent->mOverflowDeltaX = aEvent->mOverflowDeltaY = 0;
3556 } else if (isDeltaModePixel) {
3557 aEvent->mOverflowDeltaX = overflow.x;
3558 aEvent->mOverflowDeltaY = overflow.y;
3559 } else {
3560 aEvent->mOverflowDeltaX =
3561 static_cast<double>(overflow.x) / scrollAmountInDevPixels.width;
3562 aEvent->mOverflowDeltaY =
3563 static_cast<double>(overflow.y) / scrollAmountInDevPixels.height;
3564 }
3565
3566 // If CSS overflow properties caused not to scroll, the overflowDelta* values
3567 // should be same as delta* values since they may be used as gesture event by
3568 // widget. However, if there is another scrollable element in the ancestor
3569 // along the axis, probably users don't want the operation to cause
3570 // additional action such as moving history. In such case, overflowDelta
3571 // values should stay zero.
3572 if (scrollFrameWeak.IsAlive()) {
3573 if (aEvent->mDeltaX && overflowStyle.mHorizontal == StyleOverflow::Hidden &&
3574 !ComputeScrollTargetAndMayAdjustWheelEvent(
3575 aScrollContainerFrame, aEvent,
3576 COMPUTE_SCROLLABLE_ANCESTOR_ALONG_X_AXIS_WITH_AUTO_DIR)) {
3577 aEvent->mOverflowDeltaX = aEvent->mDeltaX;
3578 }
3579 if (aEvent->mDeltaY && overflowStyle.mVertical == StyleOverflow::Hidden &&
3580 !ComputeScrollTargetAndMayAdjustWheelEvent(
3581 aScrollContainerFrame, aEvent,
3582 COMPUTE_SCROLLABLE_ANCESTOR_ALONG_Y_AXIS_WITH_AUTO_DIR)) {
3583 aEvent->mOverflowDeltaY = aEvent->mDeltaY;
3584 }
3585 }
3586
3587 NS_ASSERTION(do { if (!(aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX
> 0) == (aEvent->mDeltaX > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaX is different from the scroll direction"
, "aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3590); MOZ_PretendNoReturn(); } } while (0)
3588 aEvent->mOverflowDeltaX == 0 ||do { if (!(aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX
> 0) == (aEvent->mDeltaX > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaX is different from the scroll direction"
, "aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3590); MOZ_PretendNoReturn(); } } while (0)
3589 (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0),do { if (!(aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX
> 0) == (aEvent->mDeltaX > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaX is different from the scroll direction"
, "aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3590); MOZ_PretendNoReturn(); } } while (0)
3590 "The sign of mOverflowDeltaX is different from the scroll direction")do { if (!(aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX
> 0) == (aEvent->mDeltaX > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaX is different from the scroll direction"
, "aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3590); MOZ_PretendNoReturn(); } } while (0)
;
3591 NS_ASSERTION(do { if (!(aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY
> 0) == (aEvent->mDeltaY > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaY is different from the scroll direction"
, "aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3594); MOZ_PretendNoReturn(); } } while (0)
3592 aEvent->mOverflowDeltaY == 0 ||do { if (!(aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY
> 0) == (aEvent->mDeltaY > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaY is different from the scroll direction"
, "aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3594); MOZ_PretendNoReturn(); } } while (0)
3593 (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0),do { if (!(aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY
> 0) == (aEvent->mDeltaY > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaY is different from the scroll direction"
, "aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3594); MOZ_PretendNoReturn(); } } while (0)
3594 "The sign of mOverflowDeltaY is different from the scroll direction")do { if (!(aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY
> 0) == (aEvent->mDeltaY > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaY is different from the scroll direction"
, "aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3594); MOZ_PretendNoReturn(); } } while (0)
;
3595
3596 WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(aEvent);
3597}
3598
3599void EventStateManager::DecideGestureEvent(WidgetGestureNotifyEvent* aEvent,
3600 nsIFrame* targetFrame) {
3601 NS_ASSERTION(aEvent->mMessage == eGestureNotify,do { if (!(aEvent->mMessage == eGestureNotify)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "DecideGestureEvent called with a non-gesture event"
, "aEvent->mMessage == eGestureNotify", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3602); MOZ_PretendNoReturn(); } } while (0)
3602 "DecideGestureEvent called with a non-gesture event")do { if (!(aEvent->mMessage == eGestureNotify)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "DecideGestureEvent called with a non-gesture event"
, "aEvent->mMessage == eGestureNotify", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3602); MOZ_PretendNoReturn(); } } while (0)
;
3603
3604 /* Check the ancestor tree to decide if any frame is willing* to receive
3605 * a MozPixelScroll event. If that's the case, the current touch gesture
3606 * will be used as a pan gesture; otherwise it will be a regular
3607 * mousedown/mousemove/click event.
3608 *
3609 * *willing: determine if it makes sense to pan the element using scroll
3610 * events:
3611 * - For web content: if there are any visible scrollbars on the touch point
3612 * - For XUL: if it's an scrollable element that can currently scroll in some
3613 * direction.
3614 *
3615 * Note: we'll have to one-off various cases to ensure a good usable behavior
3616 */
3617 WidgetGestureNotifyEvent::PanDirection panDirection =
3618 WidgetGestureNotifyEvent::ePanNone;
3619 bool displayPanFeedback = false;
3620 for (nsIFrame* current = targetFrame; current;
3621 current = nsLayoutUtils::GetCrossDocParentFrame(current)) {
3622 // e10s - mark remote content as pannable. This is a work around since
3623 // we don't have access to remote frame scroll info here. Apz data may
3624 // assist is solving this.
3625 if (current && IsTopLevelRemoteTarget(current->GetContent())) {
3626 panDirection = WidgetGestureNotifyEvent::ePanBoth;
3627 // We don't know when we reach bounds, so just disable feedback for now.
3628 displayPanFeedback = false;
3629 break;
3630 }
3631
3632 LayoutFrameType currentFrameType = current->Type();
3633
3634 // Scrollbars should always be draggable
3635 if (currentFrameType == LayoutFrameType::Scrollbar) {
3636 panDirection = WidgetGestureNotifyEvent::ePanNone;
3637 break;
3638 }
3639
3640 // Special check for trees
3641 if (nsTreeBodyFrame* treeFrame = do_QueryFrame(current)) {
3642 if (treeFrame->GetHorizontalOverflow()) {
3643 panDirection = WidgetGestureNotifyEvent::ePanHorizontal;
3644 }
3645 if (treeFrame->GetVerticalOverflow()) {
3646 panDirection = WidgetGestureNotifyEvent::ePanVertical;
3647 }
3648 break;
3649 }
3650
3651 if (ScrollContainerFrame* scrollContainerFrame = do_QueryFrame(current)) {
3652 layers::ScrollDirections scrollbarVisibility =
3653 scrollContainerFrame->GetScrollbarVisibility();
3654
3655 // Check if we have visible scrollbars
3656 if (scrollbarVisibility.contains(layers::ScrollDirection::eVertical)) {
3657 panDirection = WidgetGestureNotifyEvent::ePanVertical;
3658 displayPanFeedback = true;
3659 break;
3660 }
3661
3662 if (scrollbarVisibility.contains(layers::ScrollDirection::eHorizontal)) {
3663 panDirection = WidgetGestureNotifyEvent::ePanHorizontal;
3664 displayPanFeedback = true;
3665 }
3666 }
3667 } // ancestor chain
3668 aEvent->mDisplayPanFeedback = displayPanFeedback;
3669 aEvent->mPanDirection = panDirection;
3670}
3671
3672#ifdef XP_MACOSX
3673static nsINode* GetCrossDocParentNode(nsINode* aChild) {
3674 MOZ_ASSERT(aChild, "The child is null!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChild)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aChild))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aChild" " (" "The child is null!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3674); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild" ") ("
"The child is null!" ")"); do { *((volatile int*)__null) = 3674
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
3675 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3675); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 3675; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3676
3677 nsINode* parent = aChild->GetParentNode();
3678 if (parent && parent->IsContent() && aChild->IsContent()) {
3679 parent = aChild->AsContent()->GetFlattenedTreeParent();
3680 }
3681
3682 if (parent || !aChild->IsDocument()) {
3683 return parent;
3684 }
3685
3686 return aChild->AsDocument()->GetEmbedderElement();
3687}
3688
3689static bool NodeAllowsClickThrough(nsINode* aNode) {
3690 while (aNode) {
3691 if (aNode->IsAnyOfXULElements(nsGkAtoms::browser, nsGkAtoms::tree)) {
3692 return false;
3693 }
3694 if (aNode->IsAnyOfXULElements(nsGkAtoms::scrollbar, nsGkAtoms::resizer)) {
3695 return true;
3696 }
3697 aNode = GetCrossDocParentNode(aNode);
3698 }
3699 return true;
3700}
3701#endif
3702
3703void EventStateManager::PostHandleKeyboardEvent(
3704 WidgetKeyboardEvent* aKeyboardEvent, nsIFrame* aTargetFrame,
3705 nsEventStatus& aStatus) {
3706 if (aStatus == nsEventStatus_eConsumeNoDefault) {
3707 return;
3708 }
3709
3710 RefPtr<nsPresContext> presContext = mPresContext;
3711
3712 if (!aKeyboardEvent->HasBeenPostedToRemoteProcess()) {
3713 if (aKeyboardEvent->IsWaitingReplyFromRemoteProcess()) {
3714 RefPtr<BrowserParent> remote =
3715 aTargetFrame ? BrowserParent::GetFrom(aTargetFrame->GetContent())
3716 : nullptr;
3717 if (remote) {
3718 // remote is null-checked above in order to let pre-existing event
3719 // targeting code's chrome vs. content decision override in case of
3720 // disagreement in order not to disrupt non-Fission e10s mode in case
3721 // there are still bugs in the Fission-mode code. That is, if remote
3722 // is nullptr, the pre-existing event targeting code has deemed this
3723 // event to belong to chrome rather than content.
3724 BrowserParent* preciseRemote = BrowserParent::GetFocused();
3725 if (preciseRemote) {
3726 remote = preciseRemote;
3727 }
3728 // else there was a race between layout and focus tracking
3729 }
3730 if (remote && !remote->IsReadyToHandleInputEvents()) {
3731 // We need to dispatch the event to the browser element again if we were
3732 // waiting for the key reply but the event wasn't sent to the content
3733 // process due to the remote browser wasn't ready.
3734 WidgetKeyboardEvent keyEvent(*aKeyboardEvent);
3735 aKeyboardEvent->MarkAsHandledInRemoteProcess();
3736 RefPtr<Element> ownerElement = remote->GetOwnerElement();
3737 EventDispatcher::Dispatch(ownerElement, presContext, &keyEvent);
3738 if (keyEvent.DefaultPrevented()) {
3739 aKeyboardEvent->PreventDefault(!keyEvent.DefaultPreventedByContent());
3740 aStatus = nsEventStatus_eConsumeNoDefault;
3741 return;
3742 }
3743 }
3744 }
3745 // The widget expects a reply for every keyboard event. If the event wasn't
3746 // dispatched to a content process (non-e10s or no content process
3747 // running), we need to short-circuit here. Otherwise, we need to wait for
3748 // the content process to handle the event.
3749 if (aKeyboardEvent->mWidget) {
3750 aKeyboardEvent->mWidget->PostHandleKeyEvent(aKeyboardEvent);
3751 }
3752 if (aKeyboardEvent->DefaultPrevented()) {
3753 aStatus = nsEventStatus_eConsumeNoDefault;
3754 return;
3755 }
3756 }
3757
3758 // XXX Currently, our automated tests don't support mKeyNameIndex.
3759 // Therefore, we still need to handle this with keyCode.
3760 switch (aKeyboardEvent->mKeyCode) {
3761 case NS_VK_TAB:
3762 case NS_VK_F6:
3763 // This is to prevent keyboard scrolling while alt modifier in use.
3764 if (!aKeyboardEvent->IsAlt()) {
3765 aStatus = nsEventStatus_eConsumeNoDefault;
3766
3767 // Handling the tab event after it was sent to content is bad,
3768 // because to the FocusManager the remote-browser looks like one
3769 // element, so we would just move the focus to the next element
3770 // in chrome, instead of handling it in content.
3771 if (aKeyboardEvent->HasBeenPostedToRemoteProcess()) {
3772 break;
3773 }
3774
3775 EnsureDocument(presContext);
3776 nsFocusManager* fm = nsFocusManager::GetFocusManager();
3777 if (fm && mDocument) {
3778 // Shift focus forward or back depending on shift key
3779 bool isDocMove = aKeyboardEvent->IsControl() ||
3780 aKeyboardEvent->mKeyCode == NS_VK_F6;
3781 uint32_t dir =
3782 aKeyboardEvent->IsShift()
3783 ? (isDocMove ? static_cast<uint32_t>(
3784 nsIFocusManager::MOVEFOCUS_BACKWARDDOC)
3785 : static_cast<uint32_t>(
3786 nsIFocusManager::MOVEFOCUS_BACKWARD))
3787 : (isDocMove ? static_cast<uint32_t>(
3788 nsIFocusManager::MOVEFOCUS_FORWARDDOC)
3789 : static_cast<uint32_t>(
3790 nsIFocusManager::MOVEFOCUS_FORWARD));
3791 RefPtr<Element> result;
3792 fm->MoveFocus(mDocument->GetWindow(), nullptr, dir,
3793 nsIFocusManager::FLAG_BYKEY, getter_AddRefs(result));
3794 }
3795 }
3796 return;
3797 case 0:
3798 // We handle keys with no specific keycode value below.
3799 break;
3800 default:
3801 return;
3802 }
3803
3804 switch (aKeyboardEvent->mKeyNameIndex) {
3805 case KEY_NAME_INDEX_ZoomIn:
3806 case KEY_NAME_INDEX_ZoomOut:
3807 ChangeZoom(aKeyboardEvent->mKeyNameIndex == KEY_NAME_INDEX_ZoomIn);
3808 aStatus = nsEventStatus_eConsumeNoDefault;
3809 break;
3810 default:
3811 break;
3812 }
3813}
3814
3815static bool NeedsActiveContentChange(const WidgetMouseEvent* aMouseEvent) {
3816 // If the mouse event is a synthesized mouse event due to a touch, do
3817 // not set/clear the activation state. Element activation is handled by APZ.
3818 return !aMouseEvent ||
3819 aMouseEvent->mInputSource != MouseEvent_Binding::MOZ_SOURCE_TOUCH;
3820}
3821
3822nsresult EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
3823 WidgetEvent* aEvent,
3824 nsIFrame* aTargetFrame,
3825 nsEventStatus* aStatus,
3826 nsIContent* aOverrideClickTarget) {
3827 AUTO_PROFILER_LABEL("EventStateManager::PostHandleEvent", DOM)mozilla::AutoProfilerLabel raiiObject3827( "EventStateManager::PostHandleEvent"
, nullptr, JS::ProfilingCategoryPair::DOM)
;
3828 NS_ENSURE_ARG(aPresContext)do { if ((__builtin_expect(!!(!(aPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3828); return NS_ERROR_INVALID_ARG; } } while (false)
;
3829 NS_ENSURE_ARG_POINTER(aStatus)do { if ((__builtin_expect(!!(!(aStatus)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStatus" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3829); return NS_ERROR_INVALID_POINTER; } } while (false)
;
3830
3831 mCurrentTarget = aTargetFrame;
3832 mCurrentTargetContent = nullptr;
3833
3834 HandleCrossProcessEvent(aEvent, aStatus);
3835 // NOTE: the above call may have destroyed aTargetFrame, please use
3836 // mCurrentTarget henceforth. This is to avoid using it accidentally:
3837 aTargetFrame = nullptr;
3838
3839 // Most of the events we handle below require a frame.
3840 // Add special cases here.
3841 if (!mCurrentTarget && aEvent->mMessage != eMouseUp &&
3842 aEvent->mMessage != eMouseDown && aEvent->mMessage != eDragEnter &&
3843 aEvent->mMessage != eDragOver && aEvent->mMessage != ePointerUp &&
3844 aEvent->mMessage != ePointerCancel) {
3845 return NS_OK;
3846 }
3847
3848 // Keep the prescontext alive, we might need it after event dispatch
3849 RefPtr<nsPresContext> presContext = aPresContext;
3850 nsresult ret = NS_OK;
3851
3852 switch (aEvent->mMessage) {
3853 case eMouseDown: {
3854 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
3855 if (mouseEvent->mButton == MouseButton::ePrimary &&
3856 !sNormalLMouseEventInProcess) {
3857 // We got a mouseup event while a mousedown event was being processed.
3858 // Make sure that the capturing content is cleared.
3859 PresShell::ReleaseCapturingContent();
3860 break;
3861 }
3862
3863 // For remote content, capture the event in the parent process at the
3864 // <xul:browser remote> element. This will ensure that subsequent
3865 // mousemove/mouseup events will continue to be dispatched to this element
3866 // and therefore forwarded to the child.
3867 if (aEvent->HasBeenPostedToRemoteProcess() &&
3868 !PresShell::GetCapturingContent()) {
3869 if (nsIContent* content =
3870 mCurrentTarget ? mCurrentTarget->GetContent() : nullptr) {
3871 PresShell::SetCapturingContent(content, CaptureFlags::None, aEvent);
3872 } else {
3873 PresShell::ReleaseCapturingContent();
3874 }
3875 }
3876
3877 // If MouseEvent::PreventClickEvent() was called by chrome script,
3878 // we need to forget the clicking content and click count for the
3879 // following eMouseUp event.
3880 if (mouseEvent->mClickEventPrevented) {
3881 switch (mouseEvent->mButton) {
3882 case MouseButton::ePrimary:
3883 case MouseButton::eSecondary:
3884 case MouseButton::eMiddle: {
3885 LastMouseDownInfo& mouseDownInfo =
3886 GetLastMouseDownInfo(mouseEvent->mButton);
3887 mouseDownInfo.mLastMouseDownContent = nullptr;
3888 mouseDownInfo.mClickCount = 0;
3889 mouseDownInfo.mLastMouseDownInputControlType = Nothing();
3890 break;
3891 }
3892
3893 default:
3894 break;
3895 }
3896 }
3897
3898 nsCOMPtr<nsIContent> activeContent;
3899 // When content calls PreventDefault on pointerdown, we also call
3900 // PreventDefault on the subsequent mouse events to suppress default
3901 // behaviors. Normally, aStatus should be nsEventStatus_eConsumeNoDefault
3902 // when the event is DefaultPrevented but it's reset to
3903 // nsEventStatus_eIgnore in EventStateManager::PreHandleEvent. So we also
3904 // check if the event is DefaultPrevented.
3905 if (nsEventStatus_eConsumeNoDefault != *aStatus &&
3906 !aEvent->DefaultPrevented()) {
3907 nsCOMPtr<nsIContent> newFocus;
3908 bool suppressBlur = false;
3909 if (mCurrentTarget) {
3910 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(newFocus));
3911 activeContent = mCurrentTarget->GetContent();
3912
3913 // In some cases, we do not want to even blur the current focused
3914 // element. Those cases are:
3915 // 1. -moz-user-focus CSS property is set to 'ignore';
3916 // 2. XUL control element has the disabled property set to 'true'.
3917 //
3918 // We can't use nsIFrame::IsFocusable() because we want to blur when
3919 // we click on a visibility: none element.
3920 // We can't use nsIContent::IsFocusable() because we want to blur when
3921 // we click on a non-focusable element like a <div>.
3922 // We have to use |aEvent->mTarget| to not make sure we do not check
3923 // an anonymous node of the targeted element.
3924 suppressBlur =
3925 mCurrentTarget->StyleUI()->UserFocus() == StyleUserFocus::Ignore;
3926
3927 if (!suppressBlur) {
3928 if (Element* element =
3929 Element::FromEventTargetOrNull(aEvent->mTarget)) {
3930 if (nsCOMPtr<nsIDOMXULControlElement> xulControl =
3931 element->AsXULControl()) {
3932 bool disabled = false;
3933 xulControl->GetDisabled(&disabled);
3934 suppressBlur = disabled;
3935 }
3936 }
3937 }
3938 }
3939
3940 // When a root content which isn't editable but has an editable HTML
3941 // <body> element is clicked, we should redirect the focus to the
3942 // the <body> element. E.g., when an user click bottom of the editor
3943 // where is outside of the <body> element, the <body> should be focused
3944 // and the user can edit immediately after that.
3945 //
3946 // NOTE: The newFocus isn't editable that also means it's not in
3947 // designMode. In designMode, all contents are not focusable.
3948 if (newFocus && !newFocus->IsEditable()) {
3949 Document* doc = newFocus->GetComposedDoc();
3950 if (doc && newFocus == doc->GetRootElement()) {
3951 nsIContent* bodyContent =
3952 nsLayoutUtils::GetEditableRootContentByContentEditable(doc);
3953 if (bodyContent && bodyContent->GetPrimaryFrame()) {
3954 newFocus = bodyContent;
3955 }
3956 }
3957 }
3958
3959 // When the mouse is pressed, the default action is to focus the
3960 // target. Look for the nearest enclosing focusable frame.
3961 //
3962 // TODO: Probably this should be moved to Element::PostHandleEvent.
3963 for (; newFocus; newFocus = newFocus->GetFlattenedTreeParent()) {
3964 if (!newFocus->IsElement()) {
3965 continue;
3966 }
3967
3968 nsIFrame* frame = newFocus->GetPrimaryFrame();
3969 if (!frame) {
3970 continue;
3971 }
3972
3973 // If the mousedown happened inside a popup, don't try to set focus on
3974 // one of its containing elements
3975 if (frame->IsMenuPopupFrame()) {
3976 newFocus = nullptr;
3977 break;
3978 }
3979
3980 auto flags = IsFocusableFlags::WithMouse;
3981 if (frame->IsFocusable(flags)) {
3982 break;
3983 }
3984
3985 if (ShadowRoot* root = newFocus->GetShadowRoot()) {
3986 if (root->DelegatesFocus()) {
3987 if (Element* firstFocusable = root->GetFocusDelegate(flags)) {
3988 newFocus = firstFocusable;
3989 break;
3990 }
3991 }
3992 }
3993 }
3994
3995 MOZ_ASSERT_IF(newFocus, newFocus->IsElement())do { if (newFocus) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(newFocus->IsElement())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(newFocus->IsElement()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("newFocus->IsElement()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3995); AnnotateMozCrashReason("MOZ_ASSERT" "(" "newFocus->IsElement()"
")"); do { *((volatile int*)__null) = 3995; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
3996
3997 if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
3998 // if something was found to focus, focus it. Otherwise, if the
3999 // element that was clicked doesn't have -moz-user-focus: ignore,
4000 // clear the existing focus. For -moz-user-focus: ignore, the focus
4001 // is just left as is.
4002 // Another effect of mouse clicking, handled in Selection, is that
4003 // it should update the caret position to where the mouse was
4004 // clicked. Because the focus is cleared when clicking on a
4005 // non-focusable node, the next press of the tab key will cause
4006 // focus to be shifted from the caret position instead of the root.
4007 if (newFocus) {
4008 // use the mouse flag and the noscroll flag so that the content
4009 // doesn't unexpectedly scroll when clicking an element that is
4010 // only half visible
4011 uint32_t flags =
4012 nsIFocusManager::FLAG_BYMOUSE | nsIFocusManager::FLAG_NOSCROLL;
4013 // If this was a touch-generated event, pass that information:
4014 if (mouseEvent->mInputSource ==
4015 MouseEvent_Binding::MOZ_SOURCE_TOUCH) {
4016 flags |= nsIFocusManager::FLAG_BYTOUCH;
4017 }
4018 fm->SetFocus(MOZ_KnownLive(newFocus->AsElement())(newFocus->AsElement()), flags);
4019 } else if (!suppressBlur) {
4020 // clear the focus within the frame and then set it as the
4021 // focused frame
4022 EnsureDocument(mPresContext);
4023 if (mDocument) {
4024 nsCOMPtr<nsPIDOMWindowOuter> outerWindow = mDocument->GetWindow();
4025#ifdef XP_MACOSX
4026 if (!activeContent || !activeContent->IsXULElement())
4027#endif
4028 fm->ClearFocus(outerWindow);
4029 // Prevent switch frame if we're already not in the foreground tab
4030 // and we're in a content process.
4031 // TODO: If we were inactive frame in this tab, and now in
4032 // background tab, we shouldn't make the tab foreground, but
4033 // we should set focus to clicked document in the background
4034 // tab. However, nsFocusManager does not have proper method
4035 // for doing this. Therefore, we should skip setting focus
4036 // to clicked document for now.
4037 if (XRE_IsParentProcess() || IsInActiveTab(mDocument)) {
4038 fm->SetFocusedWindow(outerWindow);
4039 }
4040 }
4041 }
4042 }
4043
4044 // The rest is left button-specific.
4045 if (mouseEvent->mButton != MouseButton::ePrimary) {
4046 break;
4047 }
4048
4049 // The nearest enclosing element goes into the :active state. If we're
4050 // not an element (so we're text or something) we need to obtain
4051 // our parent element and put it into :active instead.
4052 if (activeContent && !activeContent->IsElement()) {
4053 if (nsIContent* par = activeContent->GetFlattenedTreeParent()) {
4054 activeContent = par;
4055 }
4056 }
4057 } else {
4058 // if we're here, the event handler returned false, so stop
4059 // any of our own processing of a drag. Workaround for bug 43258.
4060 StopTrackingDragGesture(true);
4061 }
4062 // XXX Why do we always set this is active? Active window may be changed
4063 // by a mousedown event listener.
4064 if (NeedsActiveContentChange(mouseEvent)) {
4065 SetActiveManager(this, activeContent);
4066 }
4067 } break;
4068 case ePointerCancel:
4069 case ePointerUp: {
4070 WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent();
4071 MOZ_ASSERT(pointerEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(pointerEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pointerEvent))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("pointerEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4071); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pointerEvent"
")"); do { *((volatile int*)__null) = 4071; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4072 // Implicitly releasing capture for given pointer. ePointerLostCapture
4073 // should be send after ePointerUp or ePointerCancel.
4074 PointerEventHandler::ImplicitlyReleasePointerCapture(pointerEvent);
4075 PointerEventHandler::UpdateActivePointerState(pointerEvent);
4076
4077 if (
4078 // After pointercancel, pointer becomes invalid so we can remove
4079 // relevant helper from table.
4080 pointerEvent->mMessage == ePointerCancel ||
4081 // pointerup for non-hoverable pointer needs to dispatch pointerout
4082 // and pointerleave events because the pointer is valid only while the
4083 // pointer is "down".
4084 !pointerEvent->InputSourceSupportsHover()) {
4085 GenerateMouseEnterExit(pointerEvent);
4086 mPointersEnterLeaveHelper.Remove(pointerEvent->pointerId);
4087 }
4088
4089 break;
4090 }
4091 case eMouseUp: {
4092 // We can unconditionally stop capturing because
4093 // we should never be capturing when the mouse button is up
4094 PresShell::ReleaseCapturingContent();
4095
4096 WidgetMouseEvent* mouseUpEvent = aEvent->AsMouseEvent();
4097 if (NeedsActiveContentChange(mouseUpEvent)) {
4098 ClearGlobalActiveContent(this);
4099 }
4100 if (mouseUpEvent && EventCausesClickEvents(*mouseUpEvent)) {
4101 // Make sure to dispatch the click even if there is no frame for
4102 // the current target element. This is required for Web compatibility.
4103 RefPtr<EventStateManager> esm =
4104 ESMFromContentOrThis(aOverrideClickTarget);
4105 ret =
4106 esm->PostHandleMouseUp(mouseUpEvent, aStatus, aOverrideClickTarget);
4107 }
4108
4109 if (PresShell* presShell = presContext->GetPresShell()) {
4110 RefPtr<nsFrameSelection> frameSelection = presShell->FrameSelection();
4111 frameSelection->SetDragState(false);
4112 }
4113 } break;
4114 case eWheelOperationEnd: {
4115 MOZ_ASSERT(aEvent->IsTrusted())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->IsTrusted())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->IsTrusted()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->IsTrusted()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4115); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsTrusted()"
")"); do { *((volatile int*)__null) = 4115; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4116 ScrollbarsForWheel::MayInactivate();
4117 WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
4118 ScrollContainerFrame* scrollTarget =
4119 ComputeScrollTargetAndMayAdjustWheelEvent(
4120 mCurrentTarget, wheelEvent,
4121 COMPUTE_DEFAULT_ACTION_TARGET_WITH_AUTO_DIR);
4122 // If the wheel event was handled by APZ, APZ will perform the scroll
4123 // snap.
4124 if (scrollTarget && !WheelTransaction::HandledByApz()) {
4125 scrollTarget->ScrollSnap();
4126 }
4127 } break;
4128 case eWheel:
4129 case eWheelOperationStart: {
4130 MOZ_ASSERT(aEvent->IsTrusted())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->IsTrusted())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->IsTrusted()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->IsTrusted()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4130); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsTrusted()"
")"); do { *((volatile int*)__null) = 4130; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4131
4132 if (*aStatus == nsEventStatus_eConsumeNoDefault) {
4133 ScrollbarsForWheel::Inactivate();
4134 break;
4135 }
4136
4137 WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
4138 MOZ_ASSERT(wheelEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(wheelEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(wheelEvent))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("wheelEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4138); AnnotateMozCrashReason("MOZ_ASSERT" "(" "wheelEvent"
")"); do { *((volatile int*)__null) = 4138; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4139
4140 // When APZ is enabled, the actual scroll animation might be handled by
4141 // the compositor.
4142 WheelPrefs::Action action =
4143 wheelEvent->mFlags.mHandledByAPZ
4144 ? WheelPrefs::ACTION_NONE
4145 : WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent);
4146
4147 WheelDeltaAdjustmentStrategy strategy =
4148 GetWheelDeltaAdjustmentStrategy(*wheelEvent);
4149 // Adjust the delta values of the wheel event if the current default
4150 // action is to horizontalize scrolling. I.e., deltaY values are set to
4151 // deltaX and deltaY and deltaZ values are set to 0.
4152 // If horizontalized, the delta values will be restored and its overflow
4153 // deltaX will become 0 when the WheelDeltaHorizontalizer instance is
4154 // being destroyed.
4155 WheelDeltaHorizontalizer horizontalizer(*wheelEvent);
4156 if (WheelDeltaAdjustmentStrategy::eHorizontalize == strategy) {
4157 horizontalizer.Horizontalize();
4158 }
4159
4160 // Since ComputeScrollTargetAndMayAdjustWheelEvent() may adjust the delta
4161 // if the event is auto-dir. So we use |ESMAutoDirWheelDeltaRestorer|
4162 // here.
4163 // An instance of |ESMAutoDirWheelDeltaRestorer| is used to monitor
4164 // auto-dir adjustment which may happen during its lifetime. If the delta
4165 // values is adjusted during its lifetime, the instance will restore the
4166 // adjusted delta when it's being destrcuted.
4167 ESMAutoDirWheelDeltaRestorer restorer(*wheelEvent);
4168 ScrollContainerFrame* scrollTarget =
4169 ComputeScrollTargetAndMayAdjustWheelEvent(
4170 mCurrentTarget, wheelEvent,
4171 COMPUTE_DEFAULT_ACTION_TARGET_WITH_AUTO_DIR);
4172
4173 switch (action) {
4174 case WheelPrefs::ACTION_SCROLL:
4175 case WheelPrefs::ACTION_HORIZONTALIZED_SCROLL: {
4176 // For scrolling of default action, we should honor the mouse wheel
4177 // transaction.
4178
4179 ScrollbarsForWheel::PrepareToScrollText(this, mCurrentTarget,
4180 wheelEvent);
4181
4182 if (aEvent->mMessage != eWheel ||
4183 (!wheelEvent->mDeltaX && !wheelEvent->mDeltaY)) {
4184 break;
4185 }
4186
4187 ScrollbarsForWheel::SetActiveScrollTarget(scrollTarget);
4188
4189 ScrollContainerFrame* rootScrollContainerFrame =
4190 !mCurrentTarget
4191 ? nullptr
4192 : mCurrentTarget->PresShell()->GetRootScrollContainerFrame();
4193 if (!scrollTarget || scrollTarget == rootScrollContainerFrame) {
4194 wheelEvent->mViewPortIsOverscrolled = true;
4195 }
4196 wheelEvent->mOverflowDeltaX = wheelEvent->mDeltaX;
4197 wheelEvent->mOverflowDeltaY = wheelEvent->mDeltaY;
4198 WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(
4199 wheelEvent);
4200 if (scrollTarget) {
4201 DoScrollText(scrollTarget, wheelEvent);
4202 } else {
4203 WheelTransaction::EndTransaction();
4204 ScrollbarsForWheel::Inactivate();
4205 }
4206 break;
4207 }
4208 case WheelPrefs::ACTION_HISTORY: {
4209 // If this event doesn't cause eLegacyMouseLineOrPageScroll event or
4210 // the direction is oblique, don't perform history back/forward.
4211 int32_t intDelta = wheelEvent->GetPreferredIntDelta();
4212 if (!intDelta) {
4213 break;
4214 }
4215 DoScrollHistory(intDelta);
4216 break;
4217 }
4218 case WheelPrefs::ACTION_ZOOM: {
4219 // If this event doesn't cause eLegacyMouseLineOrPageScroll event or
4220 // the direction is oblique, don't perform zoom in/out.
4221 int32_t intDelta = wheelEvent->GetPreferredIntDelta();
4222 if (!intDelta) {
4223 break;
4224 }
4225 DoScrollZoom(mCurrentTarget, intDelta);
4226 break;
4227 }
4228 case WheelPrefs::ACTION_NONE:
4229 default:
4230 bool allDeltaOverflown = false;
4231 if (StaticPrefs::dom_event_wheel_event_groups_enabled() &&
4232 (wheelEvent->mDeltaX != 0.0 || wheelEvent->mDeltaY != 0.0)) {
4233 if (scrollTarget) {
4234 WheelTransaction::WillHandleDefaultAction(
4235 wheelEvent, scrollTarget, mCurrentTarget);
4236 } else {
4237 WheelTransaction::EndTransaction();
4238 }
4239 }
4240 if (wheelEvent->mFlags.mHandledByAPZ) {
4241 if (wheelEvent->mCanTriggerSwipe) {
4242 // For events that can trigger swipes, APZ needs to know whether
4243 // scrolling is possible in the requested direction. It does this
4244 // by looking at the scroll overflow values on mCanTriggerSwipe
4245 // events after they have been processed.
4246 allDeltaOverflown = !ComputeScrollTarget(
4247 mCurrentTarget, wheelEvent, COMPUTE_DEFAULT_ACTION_TARGET);
4248 }
4249 } else {
4250 // The event was processed neither by APZ nor by us, so all of the
4251 // delta values must be overflown delta values.
4252 allDeltaOverflown = true;
4253 }
4254
4255 if (!allDeltaOverflown) {
4256 break;
4257 }
4258 wheelEvent->mOverflowDeltaX = wheelEvent->mDeltaX;
4259 wheelEvent->mOverflowDeltaY = wheelEvent->mDeltaY;
4260 WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(
4261 wheelEvent);
4262 wheelEvent->mViewPortIsOverscrolled = true;
4263 break;
4264 }
4265 *aStatus = nsEventStatus_eConsumeNoDefault;
4266 } break;
4267
4268 case eGestureNotify: {
4269 if (nsEventStatus_eConsumeNoDefault != *aStatus) {
4270 DecideGestureEvent(aEvent->AsGestureNotifyEvent(), mCurrentTarget);
4271 }
4272 } break;
4273
4274 case eDragEnter:
4275 case eDragOver: {
4276 NS_ASSERTION(aEvent->mClass == eDragEventClass, "Expected a drag event")do { if (!(aEvent->mClass == eDragEventClass)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Expected a drag event", "aEvent->mClass == eDragEventClass"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4276); MOZ_PretendNoReturn(); } } while (0)
;
4277
4278 // Check if the drag is occurring inside a scrollable area. If so, scroll
4279 // the area when the mouse is near the edges.
4280 if (mCurrentTarget && aEvent->mMessage == eDragOver) {
4281 nsIFrame* checkFrame = mCurrentTarget;
4282 while (checkFrame) {
4283 ScrollContainerFrame* scrollFrame = do_QueryFrame(checkFrame);
4284 // Break out so only the innermost scrollframe is scrolled.
4285 if (scrollFrame && scrollFrame->DragScroll(aEvent)) {
4286 break;
4287 }
4288 checkFrame = checkFrame->GetParent();
4289 }
4290 }
4291
4292 nsCOMPtr<nsIDragSession> dragSession =
4293 nsContentUtils::GetDragSession(mPresContext);
4294 if (!dragSession) break;
4295
4296 // Reset the flag.
4297 dragSession->SetOnlyChromeDrop(false);
4298 if (mPresContext) {
4299 EnsureDocument(mPresContext);
4300 }
4301 bool isChromeDoc = nsContentUtils::IsChromeDoc(mDocument);
4302
4303 // the initial dataTransfer is the one from the dragstart event that
4304 // was set on the dragSession when the drag began.
4305 RefPtr<DataTransfer> dataTransfer;
4306 RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer();
4307
4308 WidgetDragEvent* dragEvent = aEvent->AsDragEvent();
4309
4310 // collect any changes to moz cursor settings stored in the event's
4311 // data transfer.
4312 UpdateDragDataTransfer(dragEvent);
4313
4314 // cancelling a dragenter or dragover event means that a drop should be
4315 // allowed, so update the dropEffect and the canDrop state to indicate
4316 // that a drag is allowed. If the event isn't cancelled, a drop won't be
4317 // allowed. Essentially, to allow a drop somewhere, specify the effects
4318 // using the effectAllowed and dropEffect properties in a dragenter or
4319 // dragover event and cancel the event. To not allow a drop somewhere,
4320 // don't cancel the event or set the effectAllowed or dropEffect to
4321 // "none". This way, if the event is just ignored, no drop will be
4322 // allowed.
4323 uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
4324 uint32_t action = nsIDragService::DRAGDROP_ACTION_NONE;
4325 if (nsEventStatus_eConsumeNoDefault == *aStatus) {
4326 // If the event has initialized its mDataTransfer, use it.
4327 // Or the event has not been initialized its mDataTransfer, but
4328 // it's set before dispatch because of synthesized, but without
4329 // testing session (e.g., emulating drag from another app), use it
4330 // coming from outside.
4331 // XXX Perhaps, for the latter case, we need new API because we don't
4332 // have a chance to initialize allowed effects of the session.
4333 if (dragEvent->mDataTransfer) {
4334 // get the dataTransfer and the dropEffect that was set on it
4335 dataTransfer = dragEvent->mDataTransfer;
4336 dropEffect = dataTransfer->DropEffectInt();
4337 } else {
4338 // if dragEvent->mDataTransfer is null, it means that no attempt was
4339 // made to access the dataTransfer during the event, yet the event
4340 // was cancelled. Instead, use the initial data transfer available
4341 // from the drag session. The drop effect would not have been
4342 // initialized (which is done in DragEvent::GetDataTransfer),
4343 // so set it from the drag action. We'll still want to filter it
4344 // based on the effectAllowed below.
4345 dataTransfer = initialDataTransfer;
4346
4347 dragSession->GetDragAction(&action);
4348
4349 // filter the drop effect based on the action. Use UNINITIALIZED as
4350 // any effect is allowed.
4351 dropEffect = nsContentUtils::FilterDropEffect(
4352 action, nsIDragService::DRAGDROP_ACTION_UNINITIALIZED);
4353 }
4354
4355 // At this point, if the dataTransfer is null, it means that the
4356 // drag was originally started by directly calling the drag service.
4357 // Just assume that all effects are allowed.
4358 uint32_t effectAllowed = nsIDragService::DRAGDROP_ACTION_UNINITIALIZED;
4359 if (dataTransfer) {
4360 effectAllowed = dataTransfer->EffectAllowedInt();
4361 }
4362
4363 // set the drag action based on the drop effect and effect allowed.
4364 // The drop effect field on the drag transfer object specifies the
4365 // desired current drop effect. However, it cannot be used if the
4366 // effectAllowed state doesn't include that type of action. If the
4367 // dropEffect is "none", then the action will be 'none' so a drop will
4368 // not be allowed.
4369 if (effectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED ||
4370 dropEffect & effectAllowed)
4371 action = dropEffect;
4372
4373 if (action == nsIDragService::DRAGDROP_ACTION_NONE)
4374 dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
4375
4376 // inform the drag session that a drop is allowed on this node.
4377 dragSession->SetDragAction(action);
4378 dragSession->SetCanDrop(action != nsIDragService::DRAGDROP_ACTION_NONE);
4379
4380 // For now, do this only for dragover.
4381 // XXXsmaug dragenter needs some more work.
4382 if (aEvent->mMessage == eDragOver && !isChromeDoc) {
4383 // Someone has called preventDefault(), check whether is was on
4384 // content or chrome.
4385 dragSession->SetOnlyChromeDrop(
4386 !dragEvent->mDefaultPreventedOnContent);
4387 }
4388 } else if (aEvent->mMessage == eDragOver && !isChromeDoc) {
4389 // No one called preventDefault(), so handle drop only in chrome.
4390 dragSession->SetOnlyChromeDrop(true);
4391 }
4392 if (auto* bc = BrowserChild::GetFrom(presContext->GetDocShell())) {
4393 bc->SendUpdateDropEffect(action, dropEffect);
4394 }
4395 if (aEvent->HasBeenPostedToRemoteProcess()) {
4396 dragSession->SetCanDrop(true);
4397 } else if (initialDataTransfer) {
4398 // Now set the drop effect in the initial dataTransfer. This ensures
4399 // that we can get the desired drop effect in the drop event. For events
4400 // dispatched to content, the content process will take care of setting
4401 // this.
4402 initialDataTransfer->SetDropEffectInt(dropEffect);
4403 }
4404 } break;
4405
4406 case eDrop: {
4407 if (aEvent->mFlags.mIsSynthesizedForTests) {
4408 nsCOMPtr<nsIDragService> dragService =
4409 do_GetService("@mozilla.org/widget/dragservice;1");
4410 nsCOMPtr<nsIDragSession> dragSession =
4411 nsContentUtils::GetDragSession(mPresContext);
4412 if (dragSession && dragService &&
4413 !dragService->GetNeverAllowSessionIsSynthesizedForTests()) {
4414 MOZ_ASSERT(dragSession->IsSynthesizedForTests())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(dragSession->IsSynthesizedForTests())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(dragSession->IsSynthesizedForTests()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("dragSession->IsSynthesizedForTests()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4414); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dragSession->IsSynthesizedForTests()"
")"); do { *((volatile int*)__null) = 4414; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4415 RefPtr<WindowContext> sourceWC;
4416 DebugOnly<nsresult> rvIgnored =
4417 dragSession->GetSourceWindowContext(getter_AddRefs(sourceWC));
4418 NS_WARNING_ASSERTION(do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "nsIDragSession::GetSourceDocument() failed, but ignored"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4420); } } while (false)
4419 NS_SUCCEEDED(rvIgnored),do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "nsIDragSession::GetSourceDocument() failed, but ignored"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4420); } } while (false)
4420 "nsIDragSession::GetSourceDocument() failed, but ignored")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "nsIDragSession::GetSourceDocument() failed, but ignored"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4420); } } while (false)
;
4421 // If the drag source hasn't been initialized, i.e., dragstart was
4422 // consumed by the test, the test needs to dispatch "dragend" event
4423 // instead of the drag session. Therefore, it does not make sense
4424 // to set drag end point in such case (you hit assersion if you do
4425 // it).
4426 if (sourceWC) {
4427 CSSIntPoint dropPointInScreen =
4428 Event::GetScreenCoords(aPresContext, aEvent, aEvent->mRefPoint)
4429 .extract();
4430 dragSession->SetDragEndPointForTests(dropPointInScreen.x,
4431 dropPointInScreen.y);
4432 }
4433 }
4434 }
4435 sLastDragOverFrame = nullptr;
4436 ClearGlobalActiveContent(this);
4437 break;
4438 }
4439 case eDragExit: {
4440 // make sure to fire the enter and exit_synth events after the
4441 // eDragExit event, otherwise we'll clean up too early
4442 GenerateDragDropEnterExit(presContext, aEvent->AsDragEvent());
4443 if (auto* bc = BrowserChild::GetFrom(presContext->GetDocShell())) {
4444 // SendUpdateDropEffect to prevent nsIDragService from waiting for
4445 // response of forwarded dragexit event.
4446 bc->SendUpdateDropEffect(nsIDragService::DRAGDROP_ACTION_NONE,
4447 nsIDragService::DRAGDROP_ACTION_NONE);
4448 }
4449 break;
4450 }
4451 case eKeyUp:
4452 // If space key is released, we need to inactivate the element which was
4453 // activated by preceding space key down.
4454 // XXX Currently, we don't store the reason of activation. Therefore,
4455 // this may cancel what is activated by a mousedown, but it must not
4456 // cause actual problem in web apps in the wild since it must be
4457 // rare case that users release space key during a mouse click/drag.
4458 if (aEvent->AsKeyboardEvent()->ShouldWorkAsSpaceKey()) {
4459 ClearGlobalActiveContent(this);
4460 }
4461 break;
4462
4463 case eKeyPress: {
4464 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
4465 PostHandleKeyboardEvent(keyEvent, mCurrentTarget, *aStatus);
4466 } break;
4467
4468 case eMouseEnterIntoWidget:
4469 if (mCurrentTarget) {
4470 nsCOMPtr<nsIContent> targetContent;
4471 mCurrentTarget->GetContentForEvent(aEvent,
4472 getter_AddRefs(targetContent));
4473 SetContentState(targetContent, ElementState::HOVER);
4474 }
4475 break;
4476
4477 case eMouseExitFromWidget:
4478 PointerEventHandler::UpdateActivePointerState(aEvent->AsMouseEvent());
4479 break;
4480
4481#ifdef XP_MACOSX
4482 case eMouseActivate:
4483 if (mCurrentTarget) {
4484 nsCOMPtr<nsIContent> targetContent;
4485 mCurrentTarget->GetContentForEvent(aEvent,
4486 getter_AddRefs(targetContent));
4487 if (!NodeAllowsClickThrough(targetContent)) {
4488 *aStatus = nsEventStatus_eConsumeNoDefault;
4489 }
4490 }
4491 break;
4492#endif
4493
4494 default:
4495 break;
4496 }
4497
4498 // Reset target frame to null to avoid mistargeting after reentrant event
4499 mCurrentTarget = nullptr;
4500 mCurrentTargetContent = nullptr;
4501
4502 return ret;
4503}
4504
4505BrowserParent* EventStateManager::GetCrossProcessTarget() {
4506 return IMEStateManager::GetActiveBrowserParent();
4507}
4508
4509bool EventStateManager::IsTargetCrossProcess(WidgetGUIEvent* aEvent) {
4510 // Check to see if there is a focused, editable content in chrome,
4511 // in that case, do not forward IME events to content
4512 Element* focusedElement = GetFocusedElement();
4513 if (focusedElement && focusedElement->IsEditable()) {
4514 return false;
4515 }
4516 return IMEStateManager::GetActiveBrowserParent() != nullptr;
4517}
4518
4519void EventStateManager::NotifyDestroyPresContext(nsPresContext* aPresContext) {
4520 RefPtr<nsPresContext> presContext = aPresContext;
4521 if (presContext) {
4522 IMEStateManager::OnDestroyPresContext(*presContext);
4523 }
4524
4525 // Bug 70855: Presentation is going away, possibly for a reframe.
4526 // Reset the hover state so that if we're recreating the presentation,
4527 // we won't have the old hover state still set in the new presentation,
4528 // as if the new presentation is resized, a new element may be hovered.
4529 ResetHoverState();
4530
4531 mMouseEnterLeaveHelper = nullptr;
4532 mPointersEnterLeaveHelper.Clear();
4533 PointerEventHandler::NotifyDestroyPresContext(presContext);
4534}
4535
4536void EventStateManager::ResetHoverState() {
4537 if (mHoverContent) {
4538 SetContentState(nullptr, ElementState::HOVER);
4539 }
4540}
4541
4542void EventStateManager::SetPresContext(nsPresContext* aPresContext) {
4543 mPresContext = aPresContext;
4544}
4545
4546void EventStateManager::ClearFrameRefs(nsIFrame* aFrame) {
4547 if (aFrame && aFrame == mCurrentTarget) {
4548 mCurrentTargetContent = aFrame->GetContent();
4549 }
4550}
4551
4552struct CursorImage {
4553 gfx::IntPoint mHotspot;
4554 nsCOMPtr<imgIContainer> mContainer;
4555 ImageResolution mResolution;
4556 bool mEarlierCursorLoading = false;
4557};
4558
4559// Given the event that we're processing, and the computed cursor and hotspot,
4560// determine whether the custom CSS cursor should be blocked (that is, not
4561// honored).
4562//
4563// We will not honor it all of the following are true:
4564//
4565// * the size of the custom cursor is bigger than layout.cursor.block.max-size.
4566// * the bounds of the cursor would end up outside of the viewport of the
4567// top-level content document.
4568//
4569// This is done in order to prevent hijacking the cursor, see bug 1445844 and
4570// co.
4571static bool ShouldBlockCustomCursor(nsPresContext* aPresContext,
4572 WidgetEvent* aEvent,
4573 const CursorImage& aCursor) {
4574 int32_t width = 0;
4575 int32_t height = 0;
4576 aCursor.mContainer->GetWidth(&width);
4577 aCursor.mContainer->GetHeight(&height);
4578 aCursor.mResolution.ApplyTo(width, height);
4579
4580 int32_t maxSize = StaticPrefs::layout_cursor_block_max_size();
4581
4582 if (width <= maxSize && height <= maxSize) {
4583 return false;
4584 }
4585
4586 auto input = DOMIntersectionObserver::ComputeInput(*aPresContext->Document(),
4587 nullptr, nullptr);
4588
4589 if (!input.mRootFrame) {
4590 return false;
4591 }
4592
4593 nsPoint point = nsLayoutUtils::GetEventCoordinatesRelativeTo(
4594 aEvent, RelativeTo{input.mRootFrame});
4595
4596 // The cursor size won't be affected by our full zoom in the parent process,
4597 // so undo that before checking the rect.
4598 float zoom = aPresContext->GetFullZoom();
4599
4600 // Also adjust for accessibility cursor scaling factor.
4601 zoom /= LookAndFeel::GetFloat(LookAndFeel::FloatID::CursorScale, 1.0f);
4602
4603 nsSize size(CSSPixel::ToAppUnits(width / zoom),
4604 CSSPixel::ToAppUnits(height / zoom));
4605 nsPoint hotspot(
4606 CSSPixel::ToAppUnits(ViewAs<CSSPixel>(aCursor.mHotspot.x / zoom)),
4607 CSSPixel::ToAppUnits(ViewAs<CSSPixel>(aCursor.mHotspot.y / zoom)));
4608
4609 const nsRect cursorRect(point - hotspot, size);
4610 auto output = DOMIntersectionObserver::Intersect(input, cursorRect);
4611 return !output.mIntersectionRect ||
4612 !(*output.mIntersectionRect == cursorRect);
4613}
4614
4615static gfx::IntPoint ComputeHotspot(imgIContainer* aContainer,
4616 const Maybe<gfx::Point>& aHotspot) {
4617 MOZ_ASSERT(aContainer)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContainer)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aContainer))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aContainer", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4617); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContainer"
")"); do { *((volatile int*)__null) = 4617; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4618
4619 // css3-ui says to use the CSS-specified hotspot if present,
4620 // otherwise use the intrinsic hotspot, otherwise use the top left
4621 // corner.
4622 if (aHotspot) {
4623 int32_t imgWidth, imgHeight;
4624 aContainer->GetWidth(&imgWidth);
4625 aContainer->GetHeight(&imgHeight);
4626 auto hotspot = gfx::IntPoint::Round(*aHotspot);
4627 return {std::max(std::min(hotspot.x.value, imgWidth - 1), 0),
4628 std::max(std::min(hotspot.y.value, imgHeight - 1), 0)};
4629 }
4630
4631 gfx::IntPoint hotspot;
4632 aContainer->GetHotspotX(&hotspot.x.value);
4633 aContainer->GetHotspotY(&hotspot.y.value);
4634 return hotspot;
4635}
4636
4637static CursorImage ComputeCustomCursor(nsPresContext* aPresContext,
4638 WidgetEvent* aEvent,
4639 const nsIFrame& aFrame,
4640 const nsIFrame::Cursor& aCursor) {
4641 if (aCursor.mAllowCustomCursor == nsIFrame::AllowCustomCursorImage::No) {
4642 return {};
4643 }
4644 const ComputedStyle& style =
4645 aCursor.mStyle ? *aCursor.mStyle : *aFrame.Style();
4646
4647 // If we are falling back because any cursor before us is loading, let the
4648 // consumer know.
4649 bool loading = false;
4650 for (const auto& image : style.StyleUI()->Cursor().images.AsSpan()) {
4651 MOZ_ASSERT(image.image.IsImageRequestType(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(image.image.IsImageRequestType())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(image.image.IsImageRequestType
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("image.image.IsImageRequestType()" " (" "Cursor image should only parse url() types"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4652); AnnotateMozCrashReason("MOZ_ASSERT" "(" "image.image.IsImageRequestType()"
") (" "Cursor image should only parse url() types" ")"); do {
*((volatile int*)__null) = 4652; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
4652 "Cursor image should only parse url() types")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(image.image.IsImageRequestType())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(image.image.IsImageRequestType
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("image.image.IsImageRequestType()" " (" "Cursor image should only parse url() types"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4652); AnnotateMozCrashReason("MOZ_ASSERT" "(" "image.image.IsImageRequestType()"
") (" "Cursor image should only parse url() types" ")"); do {
*((volatile int*)__null) = 4652; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
4653 uint32_t status;
4654 imgRequestProxy* req = image.image.GetImageRequest();
4655 if (!req || NS_FAILED(req->GetImageStatus(&status))((bool)(__builtin_expect(!!(NS_FAILED_impl(req->GetImageStatus
(&status))), 0)))
) {
4656 continue;
4657 }
4658 if (!(status & imgIRequest::STATUS_LOAD_COMPLETE)) {
4659 loading = true;
4660 continue;
4661 }
4662 if (status & imgIRequest::STATUS_ERROR) {
4663 continue;
4664 }
4665 nsCOMPtr<imgIContainer> container;
4666 req->GetImage(getter_AddRefs(container));
4667 if (!container) {
4668 continue;
4669 }
4670 StyleImageOrientation orientation =
4671 aFrame.StyleVisibility()->UsedImageOrientation(req);
4672 container = nsLayoutUtils::OrientImage(container, orientation);
4673 Maybe<gfx::Point> specifiedHotspot =
4674 image.has_hotspot ? Some(gfx::Point{image.hotspot_x, image.hotspot_y})
4675 : Nothing();
4676 gfx::IntPoint hotspot = ComputeHotspot(container, specifiedHotspot);
4677 CursorImage result{hotspot, std::move(container),
4678 image.image.GetResolution(style), loading};
4679 if (ShouldBlockCustomCursor(aPresContext, aEvent, result)) {
4680 continue;
4681 }
4682 // This is the one we want!
4683 return result;
4684 }
4685 return {{}, nullptr, {}, loading};
4686}
4687
4688void EventStateManager::UpdateCursor(nsPresContext* aPresContext,
4689 WidgetMouseEvent* aEvent,
4690 nsIFrame* aTargetFrame,
4691 nsEventStatus* aStatus) {
4692 if (aTargetFrame && IsRemoteTarget(aTargetFrame->GetContent())) {
4693 return;
4694 }
4695
4696 auto cursor = StyleCursorKind::Default;
4697 nsCOMPtr<imgIContainer> container;
4698 ImageResolution resolution;
4699 Maybe<gfx::IntPoint> hotspot;
4700
4701 if (mHidingCursorWhileTyping && aEvent->IsReal()) {
4702 // Any non-synthetic mouse event makes us show the cursor again.
4703 mHidingCursorWhileTyping = false;
4704 }
4705
4706 if (mHidingCursorWhileTyping) {
4707 cursor = StyleCursorKind::None;
4708 } else if (mLockCursor != kInvalidCursorKind) {
4709 // If cursor is locked just use the locked one
4710 cursor = mLockCursor;
4711 } else if (aTargetFrame) {
4712 // If not locked, look for correct cursor
4713 nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(
4714 aEvent, RelativeTo{aTargetFrame});
4715 const nsIFrame::Cursor framecursor = aTargetFrame->GetCursor(pt);
4716 const CursorImage customCursor =
4717 ComputeCustomCursor(aPresContext, aEvent, *aTargetFrame, framecursor);
4718
4719 // If the current cursor is from the same frame, and it is now
4720 // loading some new image for the cursor, we should wait for a
4721 // while rather than taking its fallback cursor directly.
4722 if (customCursor.mEarlierCursorLoading &&
4723 gLastCursorSourceFrame == aTargetFrame &&
4724 TimeStamp::NowLoRes() - gLastCursorUpdateTime <
4725 TimeDuration::FromMilliseconds(kCursorLoadingTimeout)) {
4726 return;
4727 }
4728 cursor = framecursor.mCursor;
4729 container = std::move(customCursor.mContainer);
4730 resolution = customCursor.mResolution;
4731 hotspot = Some(customCursor.mHotspot);
4732 }
4733
4734 if (aTargetFrame) {
4735 if (cursor == StyleCursorKind::Pointer && IsSelectingLink(aTargetFrame)) {
4736 cursor = aTargetFrame->GetWritingMode().IsVertical()
4737 ? StyleCursorKind::VerticalText
4738 : StyleCursorKind::Text;
4739 }
4740 SetCursor(cursor, container, resolution, hotspot,
4741 aTargetFrame->GetNearestWidget(), false);
4742 gLastCursorSourceFrame = aTargetFrame;
4743 gLastCursorUpdateTime = TimeStamp::NowLoRes();
4744 }
4745
4746 if (mLockCursor != kInvalidCursorKind || StyleCursorKind::Auto != cursor) {
4747 *aStatus = nsEventStatus_eConsumeDoDefault;
4748 }
4749}
4750
4751void EventStateManager::ClearCachedWidgetCursor(nsIFrame* aTargetFrame) {
4752 if (!aTargetFrame) {
4753 return;
4754 }
4755 nsIWidget* aWidget = aTargetFrame->GetNearestWidget();
4756 if (!aWidget) {
4757 return;
4758 }
4759 aWidget->ClearCachedCursor();
4760}
4761
4762void EventStateManager::StartHidingCursorWhileTyping(nsIWidget* aWidget) {
4763 if (mHidingCursorWhileTyping || sCursorSettingManager != this) {
4764 return;
4765 }
4766 mHidingCursorWhileTyping = true;
4767 SetCursor(StyleCursorKind::None, nullptr, {}, {}, aWidget, false);
4768}
4769
4770nsresult EventStateManager::SetCursor(StyleCursorKind aCursor,
4771 imgIContainer* aContainer,
4772 const ImageResolution& aResolution,
4773 const Maybe<gfx::IntPoint>& aHotspot,
4774 nsIWidget* aWidget, bool aLockCursor) {
4775 EnsureDocument(mPresContext);
4776 NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(mDocument)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mDocument" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4776); return NS_ERROR_FAILURE; } } while (false)
;
4777 sCursorSettingManager = this;
4778
4779 NS_ENSURE_TRUE(aWidget, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(aWidget)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aWidget" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4779); return NS_ERROR_FAILURE; } } while (false)
;
4780 if (aLockCursor) {
4781 if (StyleCursorKind::Auto != aCursor) {
4782 mLockCursor = aCursor;
4783 } else {
4784 // If cursor style is set to auto we unlock the cursor again.
4785 mLockCursor = kInvalidCursorKind;
4786 }
4787 }
4788 nsCursor c;
4789 switch (aCursor) {
4790 case StyleCursorKind::Auto:
4791 case StyleCursorKind::Default:
4792 c = eCursor_standard;
4793 break;
4794 case StyleCursorKind::Pointer:
4795 c = eCursor_hyperlink;
4796 break;
4797 case StyleCursorKind::Crosshair:
4798 c = eCursor_crosshair;
4799 break;
4800 case StyleCursorKind::Move:
4801 c = eCursor_move;
4802 break;
4803 case StyleCursorKind::Text:
4804 c = eCursor_select;
4805 break;
4806 case StyleCursorKind::Wait:
4807 c = eCursor_wait;
4808 break;
4809 case StyleCursorKind::Help:
4810 c = eCursor_help;
4811 break;
4812 case StyleCursorKind::NResize:
4813 c = eCursor_n_resize;
4814 break;
4815 case StyleCursorKind::SResize:
4816 c = eCursor_s_resize;
4817 break;
4818 case StyleCursorKind::WResize:
4819 c = eCursor_w_resize;
4820 break;
4821 case StyleCursorKind::EResize:
4822 c = eCursor_e_resize;
4823 break;
4824 case StyleCursorKind::NwResize:
4825 c = eCursor_nw_resize;
4826 break;
4827 case StyleCursorKind::SeResize:
4828 c = eCursor_se_resize;
4829 break;
4830 case StyleCursorKind::NeResize:
4831 c = eCursor_ne_resize;
4832 break;
4833 case StyleCursorKind::SwResize:
4834 c = eCursor_sw_resize;
4835 break;
4836 case StyleCursorKind::Copy: // CSS3
4837 c = eCursor_copy;
4838 break;
4839 case StyleCursorKind::Alias:
4840 c = eCursor_alias;
4841 break;
4842 case StyleCursorKind::ContextMenu:
4843 c = eCursor_context_menu;
4844 break;
4845 case StyleCursorKind::Cell:
4846 c = eCursor_cell;
4847 break;
4848 case StyleCursorKind::Grab:
4849 c = eCursor_grab;
4850 break;
4851 case StyleCursorKind::Grabbing:
4852 c = eCursor_grabbing;
4853 break;
4854 case StyleCursorKind::Progress:
4855 c = eCursor_spinning;
4856 break;
4857 case StyleCursorKind::ZoomIn:
4858 c = eCursor_zoom_in;
4859 break;
4860 case StyleCursorKind::ZoomOut:
4861 c = eCursor_zoom_out;
4862 break;
4863 case StyleCursorKind::NotAllowed:
4864 c = eCursor_not_allowed;
4865 break;
4866 case StyleCursorKind::ColResize:
4867 c = eCursor_col_resize;
4868 break;
4869 case StyleCursorKind::RowResize:
4870 c = eCursor_row_resize;
4871 break;
4872 case StyleCursorKind::NoDrop:
4873 c = eCursor_no_drop;
4874 break;
4875 case StyleCursorKind::VerticalText:
4876 c = eCursor_vertical_text;
4877 break;
4878 case StyleCursorKind::AllScroll:
4879 c = eCursor_all_scroll;
4880 break;
4881 case StyleCursorKind::NeswResize:
4882 c = eCursor_nesw_resize;
4883 break;
4884 case StyleCursorKind::NwseResize:
4885 c = eCursor_nwse_resize;
4886 break;
4887 case StyleCursorKind::NsResize:
4888 c = eCursor_ns_resize;
4889 break;
4890 case StyleCursorKind::EwResize:
4891 c = eCursor_ew_resize;
4892 break;
4893 case StyleCursorKind::None:
4894 c = eCursor_none;
4895 break;
4896 default:
4897 MOZ_ASSERT_UNREACHABLE("Unknown cursor kind")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Unknown cursor kind" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4897); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unknown cursor kind" ")"); do { *
((volatile int*)__null) = 4897; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
4898 c = eCursor_standard;
4899 break;
4900 }
4901
4902 uint32_t x = aHotspot ? aHotspot->x.value : 0;
4903 uint32_t y = aHotspot ? aHotspot->y.value : 0;
4904 aWidget->SetCursor(nsIWidget::Cursor{c, aContainer, x, y, aResolution});
4905 return NS_OK;
4906}
4907
4908bool EventStateManager::CursorSettingManagerHasLockedCursor() {
4909 return sCursorSettingManager &&
4910 sCursorSettingManager->mLockCursor != kInvalidCursorKind;
4911}
4912
4913class MOZ_STACK_CLASS ESMEventCB : public EventDispatchingCallback {
4914 public:
4915 explicit ESMEventCB(nsIContent* aTarget) : mTarget(aTarget) {}
4916
4917 MOZ_CAN_RUN_SCRIPT
4918 void HandleEvent(EventChainPostVisitor& aVisitor) override {
4919 if (aVisitor.mPresContext) {
4920 nsIFrame* frame = aVisitor.mPresContext->GetPrimaryFrameFor(mTarget);
4921 if (frame) {
4922 frame->HandleEvent(aVisitor.mPresContext, aVisitor.mEvent->AsGUIEvent(),
4923 &aVisitor.mEventStatus);
4924 }
4925 }
4926 }
4927
4928 nsCOMPtr<nsIContent> mTarget;
4929};
4930
4931static UniquePtr<WidgetMouseEvent> CreateMouseOrPointerWidgetEvent(
4932 WidgetMouseEvent* aMouseEvent, EventMessage aMessage,
4933 EventTarget* aRelatedTarget) {
4934 // This method does not support creating a mouse/pointer button change event
4935 // because of no data about the changing state.
4936 MOZ_ASSERT(aMessage != eMouseDown)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage != eMouseDown)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage != eMouseDown))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aMessage != eMouseDown"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4936); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != eMouseDown"
")"); do { *((volatile int*)__null) = 4936; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4937 MOZ_ASSERT(aMessage != eMouseUp)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage != eMouseUp)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage != eMouseUp))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("aMessage != eMouseUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4937); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != eMouseUp"
")"); do { *((volatile int*)__null) = 4937; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4938 MOZ_ASSERT(aMessage != ePointerDown)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage != ePointerDown)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage != ePointerDown))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aMessage != ePointerDown"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4938); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != ePointerDown"
")"); do { *((volatile int*)__null) = 4938; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4939 MOZ_ASSERT(aMessage != ePointerUp)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage != ePointerUp)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage != ePointerUp))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aMessage != ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4939); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != ePointerUp"
")"); do { *((volatile int*)__null) = 4939; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4940 // This method is currently designed to create the following events.
4941 MOZ_ASSERT(aMessage == eMouseOver || aMessage == eMouseEnter ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4946; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4942 aMessage == eMouseOut || aMessage == eMouseLeave ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4946; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4943 aMessage == ePointerOver || aMessage == ePointerEnter ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4946; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4944 aMessage == ePointerOut || aMessage == ePointerLeave ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4946; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4945 aMessage == eMouseEnterIntoWidget ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4946; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4946 aMessage == eMouseExitFromWidget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4946; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4947
4948 WidgetPointerEvent* sourcePointer = aMouseEvent->AsPointerEvent();
4949 UniquePtr<WidgetMouseEvent> newEvent;
4950 if (sourcePointer) {
4951 AUTO_PROFILER_LABEL("CreateMouseOrPointerWidgetEvent", OTHER)mozilla::AutoProfilerLabel raiiObject4951( "CreateMouseOrPointerWidgetEvent"
, nullptr, JS::ProfilingCategoryPair::OTHER)
;
4952
4953 WidgetPointerEvent* newPointerEvent = new WidgetPointerEvent(
4954 aMouseEvent->IsTrusted(), aMessage, aMouseEvent->mWidget);
4955 newPointerEvent->mIsPrimary = sourcePointer->mIsPrimary;
4956 newPointerEvent->mWidth = sourcePointer->mWidth;
4957 newPointerEvent->mHeight = sourcePointer->mHeight;
4958 newPointerEvent->mInputSource = sourcePointer->mInputSource;
4959
4960 newEvent = WrapUnique(newPointerEvent);
4961 } else {
4962 newEvent = MakeUnique<WidgetMouseEvent>(aMouseEvent->IsTrusted(), aMessage,
4963 aMouseEvent->mWidget,
4964 WidgetMouseEvent::eReal);
4965 }
4966
4967 // Inherit whether the event is synthesized by the test API or not.
4968 // Then, when the event is synthesized by a test API and handled in a remote
4969 // process, it won't be ignored. See PresShell::HandleEvent().
4970 newEvent->mFlags.mIsSynthesizedForTests =
4971 aMouseEvent->mFlags.mIsSynthesizedForTests;
4972
4973 newEvent->mRelatedTarget = aRelatedTarget;
4974 newEvent->mRefPoint = aMouseEvent->mRefPoint;
4975 newEvent->mModifiers = aMouseEvent->mModifiers;
4976 if (!aMouseEvent->mFlags.mDispatchedAtLeastOnce &&
4977 aMouseEvent->InputSourceSupportsHover()) {
4978 // If we synthesize a pointer event or a mouse event from another event
4979 // which changes a button state whose input soucre supports hover state and
4980 // the source event has not been dispatched yet, we should set to the button
4981 // state of the synthesizing event to previous one.
4982 // Note that we don't need to do this if the input source does not support
4983 // hover state because a WPT check the behavior (see below) and the other
4984 // browsers pass the test even though this is inconsistent behavior.
4985 newEvent->mButton =
4986 sourcePointer ? MouseButton::eNotPressed : MouseButton::ePrimary;
4987 if (aMouseEvent->IsPressingButton()) {
4988 // If the source event has not been dispatched into the DOM yet, we
4989 // need to remove the flag which is being pressed.
4990 newEvent->mButtons = static_cast<decltype(WidgetMouseEvent::mButtons)>(
4991 aMouseEvent->mButtons &
4992 ~MouseButtonsFlagToChange(
4993 static_cast<MouseButton>(aMouseEvent->mButton)));
4994 } else if (aMouseEvent->IsReleasingButton()) {
4995 // If the source event has not been dispatched into the DOM yet, we
4996 // need to add the flag which is being released.
4997 newEvent->mButtons = static_cast<decltype(WidgetMouseEvent::mButtons)>(
4998 aMouseEvent->mButtons |
4999 MouseButtonsFlagToChange(
5000 static_cast<MouseButton>(aMouseEvent->mButton)));
5001 } else {
5002 // The source event does not change the buttons state so that we can
5003 // set mButtons value as-is.
5004 newEvent->mButtons = aMouseEvent->mButtons;
5005 }
5006 // Adjust pressure if it does not matches with mButtons.
5007 // FIXME: We may use wrong pressure value if the source event has not been
5008 // dispatched into the DOM yet. However, fixing this requires to store the
5009 // last pressure value somewhere.
5010 if (newEvent->mButtons && aMouseEvent->mPressure == 0) {
5011 newEvent->mPressure = 0.5f;
5012 } else if (!newEvent->mButtons && aMouseEvent->mPressure != 0) {
5013 newEvent->mPressure = 0;
5014 } else {
5015 newEvent->mPressure = aMouseEvent->mPressure;
5016 }
5017 } else {
5018 // If the event has already been dispatched into the tree, web apps has
5019 // already handled the button state change, so the button state of the
5020 // source event has already synced.
5021 // If the input source does not have hover state, we don't need to modify
5022 // the state because the other browsers behave so and tested by
5023 // pointerevent_attributes_nohover_pointers.html even though this is
5024 // different expectation from
5025 // pointerevent_attributes_hoverable_pointers.html, but the other browsers
5026 // pass both of them.
5027 newEvent->mButton = aMouseEvent->mButton;
5028 newEvent->mButtons = aMouseEvent->mButtons;
5029 newEvent->mPressure = aMouseEvent->mPressure;
5030 }
5031
5032 newEvent->mInputSource = aMouseEvent->mInputSource;
5033 newEvent->pointerId = aMouseEvent->pointerId;
5034
5035 return newEvent;
5036}
5037
5038already_AddRefed<nsIWidget>
5039EventStateManager::DispatchMouseOrPointerBoundaryEvent(
5040 WidgetMouseEvent* aMouseEvent, EventMessage aMessage,
5041 nsIContent* aTargetContent, nsIContent* aRelatedContent) {
5042 MOZ_ASSERT(aMessage == eMouseEnter || aMessage == ePointerEnter ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseEnter || aMessage == ePointerEnter
|| aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage
== eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut
|| aMessage == ePointerOut)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseEnter || aMessage
== ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave
|| aMessage == eMouseOver || aMessage == ePointerOver || aMessage
== eMouseOut || aMessage == ePointerOut))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5045); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5045; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5043 aMessage == eMouseLeave || aMessage == ePointerLeave ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseEnter || aMessage == ePointerEnter
|| aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage
== eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut
|| aMessage == ePointerOut)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseEnter || aMessage
== ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave
|| aMessage == eMouseOver || aMessage == ePointerOver || aMessage
== eMouseOut || aMessage == ePointerOut))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5045); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5045; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5044 aMessage == eMouseOver || aMessage == ePointerOver ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseEnter || aMessage == ePointerEnter
|| aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage
== eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut
|| aMessage == ePointerOut)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseEnter || aMessage
== ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave
|| aMessage == eMouseOver || aMessage == ePointerOver || aMessage
== eMouseOut || aMessage == ePointerOut))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5045); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5045; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5045 aMessage == eMouseOut || aMessage == ePointerOut)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseEnter || aMessage == ePointerEnter
|| aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage
== eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut
|| aMessage == ePointerOut)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseEnter || aMessage
== ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave
|| aMessage == eMouseOver || aMessage == ePointerOver || aMessage
== eMouseOut || aMessage == ePointerOut))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5045); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5045; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5046
5047 // https://w3c.github.io/pointerlock/#dom-element-requestpointerlock
5048 // "[Once in the locked state...E]vents that require the concept
5049 // of a mouse cursor must not be dispatched (for example: mouseover,
5050 // mouseout...).
5051 // XXXedgar should we also block pointer events?
5052 if (PointerLockManager::IsLocked() &&
5053 (aMessage == eMouseLeave || aMessage == eMouseEnter ||
5054 aMessage == eMouseOver || aMessage == eMouseOut)) {
5055 mCurrentTargetContent = nullptr;
5056 nsCOMPtr<Element> pointerLockedElement =
5057 PointerLockManager::GetLockedElement();
5058 if (!pointerLockedElement) {
5059 NS_WARNING("Should have pointer locked element, but didn't.")NS_DebugBreak(NS_DEBUG_WARNING, "Should have pointer locked element, but didn't."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5059)
;
5060 return nullptr;
5061 }
5062 nsIFrame* const pointerLockedFrame =
5063 mPresContext->GetPrimaryFrameFor(pointerLockedElement);
5064 if (NS_WARN_IF(!pointerLockedFrame)NS_warn_if_impl(!pointerLockedFrame, "!pointerLockedFrame", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5064)
) {
5065 return nullptr;
5066 }
5067 return do_AddRef(pointerLockedFrame->GetNearestWidget());
5068 }
5069
5070 mCurrentTargetContent = nullptr;
5071
5072 if (!aTargetContent) {
5073 return nullptr;
5074 }
5075
5076 // Store the widget before dispatching the event because some event listeners
5077 // of the dispatching event may cause reframe the target or remove the target
5078 // from the tree.
5079 nsCOMPtr<nsIWidget> targetWidget;
5080 if (nsIFrame* const targetFrame =
5081 mPresContext->GetPrimaryFrameFor(aTargetContent)) {
5082 targetWidget = targetFrame->GetNearestWidget();
5083 }
5084
5085 nsCOMPtr<nsIContent> targetContent = aTargetContent;
5086 nsCOMPtr<nsIContent> relatedContent = aRelatedContent;
5087
5088 UniquePtr<WidgetMouseEvent> dispatchEvent =
5089 CreateMouseOrPointerWidgetEvent(aMouseEvent, aMessage, relatedContent);
5090
5091 AutoWeakFrame previousTarget = mCurrentTarget;
5092 mCurrentTargetContent = targetContent;
5093
5094 nsEventStatus status = nsEventStatus_eIgnore;
5095 ESMEventCB callback(targetContent);
5096 RefPtr<nsPresContext> presContext = mPresContext;
5097 EventDispatcher::Dispatch(targetContent, presContext, dispatchEvent.get(),
5098 nullptr, &status, &callback);
5099
5100 if (mPresContext) {
5101 // If we are entering/leaving remote content, dispatch a mouse enter/exit
5102 // event to the remote frame.
5103 if (IsTopLevelRemoteTarget(targetContent)) {
5104 if (aMessage == eMouseOut) {
5105 // For remote content, send a puppet widget mouse exit event.
5106 UniquePtr<WidgetMouseEvent> remoteEvent =
5107 CreateMouseOrPointerWidgetEvent(aMouseEvent, eMouseExitFromWidget,
5108 relatedContent);
5109 remoteEvent->mExitFrom = Some(WidgetMouseEvent::ePuppet);
5110
5111 // mCurrentTarget is set to the new target, so we must reset it to the
5112 // old target and then dispatch a cross-process event. (mCurrentTarget
5113 // will be set back below.) HandleCrossProcessEvent will query for the
5114 // proper target via GetEventTarget which will return mCurrentTarget.
5115 mCurrentTarget = mPresContext->GetPrimaryFrameFor(targetContent);
5116 HandleCrossProcessEvent(remoteEvent.get(), &status);
5117 } else if (aMessage == eMouseOver) {
5118 UniquePtr<WidgetMouseEvent> remoteEvent =
5119 CreateMouseOrPointerWidgetEvent(aMouseEvent, eMouseEnterIntoWidget,
5120 relatedContent);
5121 HandleCrossProcessEvent(remoteEvent.get(), &status);
5122 }
5123 }
5124 }
5125
5126 mCurrentTargetContent = nullptr;
5127 mCurrentTarget = previousTarget;
5128
5129 return targetWidget.forget();
5130}
5131
5132static nsIContent* FindCommonAncestor(nsIContent* aNode1, nsIContent* aNode2) {
5133 if (!aNode1 || !aNode2) {
5134 return nullptr;
5135 }
5136 return nsContentUtils::GetCommonFlattenedTreeAncestor(aNode1, aNode2);
5137}
5138
5139class EnterLeaveDispatcher {
5140 public:
5141 EnterLeaveDispatcher(EventStateManager* aESM, nsIContent* aTarget,
5142 nsIContent* aRelatedTarget,
5143 WidgetMouseEvent* aMouseEvent,
5144 EventMessage aEventMessage)
5145 : mESM(aESM), mMouseEvent(aMouseEvent), mEventMessage(aEventMessage) {
5146 nsPIDOMWindowInner* win =
5147 aTarget ? aTarget->OwnerDoc()->GetInnerWindow() : nullptr;
5148 if (aMouseEvent->AsPointerEvent()
5149 ? win && win->HasPointerEnterLeaveEventListeners()
5150 : win && win->HasMouseEnterLeaveEventListeners()) {
5151 mRelatedTarget =
5152 aRelatedTarget ? aRelatedTarget->FindFirstNonChromeOnlyAccessContent()
5153 : nullptr;
5154 nsINode* commonParent = FindCommonAncestor(aTarget, aRelatedTarget);
5155 nsIContent* current = aTarget;
5156 // Note, it is ok if commonParent is null!
5157 while (current && current != commonParent) {
5158 if (!current->ChromeOnlyAccess()) {
5159 mTargets.AppendObject(current);
5160 }
5161 // mouseenter/leave is fired only on elements.
5162 current = current->GetFlattenedTreeParent();
5163 }
5164 }
5165 }
5166
5167 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
5168 MOZ_CAN_RUN_SCRIPT_BOUNDARY void Dispatch() {
5169 if (mEventMessage == eMouseEnter || mEventMessage == ePointerEnter) {
5170 for (int32_t i = mTargets.Count() - 1; i >= 0; --i) {
5171 nsCOMPtr<nsIWidget> widget = mESM->DispatchMouseOrPointerBoundaryEvent(
5172 mMouseEvent, mEventMessage, MOZ_KnownLive(mTargets[i])(mTargets[i]),
5173 mRelatedTarget);
5174 }
5175 } else {
5176 for (int32_t i = 0; i < mTargets.Count(); ++i) {
5177 nsCOMPtr<nsIWidget> widget = mESM->DispatchMouseOrPointerBoundaryEvent(
5178 mMouseEvent, mEventMessage, MOZ_KnownLive(mTargets[i])(mTargets[i]),
5179 mRelatedTarget);
5180 }
5181 }
5182 }
5183
5184 // Nothing overwrites anything after constructor. Please remove MOZ_KnownLive
5185 // and MOZ_KNOWN_LIVE if anything marked as such becomes mutable.
5186 const RefPtr<EventStateManager> mESM;
5187 nsCOMArray<nsIContent> mTargets;
5188 MOZ_KNOWN_LIVE nsCOMPtr<nsIContent> mRelatedTarget;
5189 WidgetMouseEvent* mMouseEvent;
5190 EventMessage mEventMessage;
5191};
5192
5193void EventStateManager::NotifyMouseOut(WidgetMouseEvent* aMouseEvent,
5194 nsIContent* aMovingInto) {
5195 const bool isPointer = aMouseEvent->mClass == ePointerEventClass;
5196 LogModule* const logModule =
5197 isPointer ? sPointerBoundaryLog : sMouseBoundaryLog;
5198
5199 RefPtr<OverOutElementsWrapper> wrapper = GetWrapperByEventID(aMouseEvent);
5200
5201 // If there is no deepest "leave" event target, that means the last "over"
5202 // target has already been removed from the tree. Therefore, checking only
5203 // the "leave" event target is enough.
5204 if (!wrapper || !wrapper->GetDeepestLeaveEventTarget()) {
5205 return;
5206 }
5207 // Before firing "out" and/or "leave" events, check for recursion
5208 if (wrapper->IsDispatchingOutEventOnLastOverEventTarget()) {
5209 return;
5210 }
5211
5212 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOut: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5213 ("NotifyMouseOut: the source event is %s (IsReal()=%s)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOut: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5214 ToChar(aMouseEvent->mMessage),do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOut: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5215 aMouseEvent->IsReal() ? "true" : "false"))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOut: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
;
5216
5217 // XXX If a content node is a container of remove content, it should be
5218 // replaced with them and its children should not be visible. Therefore,
5219 // if the deepest "enter" target is not the last "over" target, i.e., the
5220 // last "over" target has been removed from the DOM tree, it means that the
5221 // child/descendant was not replaced by remote content. So,
5222 // wrapper->GetOutEventTaget() may be enough here.
5223 if (RefPtr<nsFrameLoaderOwner> flo =
5224 do_QueryObject(wrapper->GetDeepestLeaveEventTarget())) {
5225 if (BrowsingContext* bc = flo->GetExtantBrowsingContext()) {
5226 if (nsIDocShell* docshell = bc->GetDocShell()) {
5227 if (RefPtr<nsPresContext> presContext = docshell->GetPresContext()) {
5228 EventStateManager* kidESM = presContext->EventStateManager();
5229 // Not moving into any element in this subdocument
5230 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying child EventStateManager (%p) of \"out\" "
"event...", kidESM); } } while (0)
5231 ("Notifying child EventStateManager (%p) of \"out\" "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying child EventStateManager (%p) of \"out\" "
"event...", kidESM); } } while (0)
5232 "event...",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying child EventStateManager (%p) of \"out\" "
"event...", kidESM); } } while (0)
5233 kidESM))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying child EventStateManager (%p) of \"out\" "
"event...", kidESM); } } while (0)
;
5234 kidESM->NotifyMouseOut(aMouseEvent, nullptr);
5235 }
5236 }
5237 }
5238 }
5239 // That could have caused DOM events which could wreak havoc. Reverify
5240 // things and be careful.
5241 if (!wrapper->GetDeepestLeaveEventTarget()) {
5242 return;
5243 }
5244
5245 wrapper->WillDispatchOutAndOrLeaveEvent();
5246
5247 // Don't touch hover state if aMovingInto is non-null. Caller will update
5248 // hover state itself, and we have optimizations for hover switching between
5249 // two nearby elements both deep in the DOM tree that would be defeated by
5250 // switching the hover state to null here.
5251 if (!aMovingInto && !isPointer) {
5252 // Unset :hover
5253 SetContentState(nullptr, ElementState::HOVER);
5254 }
5255
5256 EnterLeaveDispatcher leaveDispatcher(
5257 this, wrapper->GetDeepestLeaveEventTarget(), aMovingInto, aMouseEvent,
5258 isPointer ? ePointerLeave : eMouseLeave);
5259
5260 // "out" events hould be fired only when the deepest "leave" event target
5261 // is the last "over" event target.
5262 if (nsCOMPtr<nsIContent> outEventTarget = wrapper->GetOutEventTarget()) {
5263 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
5264 ("Dispatching %s event to %s (%p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
5265 isPointer ? "ePointerOut" : "eMouseOut",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
5266 outEventTarget ? ToString(*outEventTarget).c_str() : "nullptr",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
5267 outEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
;
5268 nsCOMPtr<nsIWidget> widget = DispatchMouseOrPointerBoundaryEvent(
5269 aMouseEvent, isPointer ? ePointerOut : eMouseOut, outEventTarget,
5270 aMovingInto);
5271 }
5272
5273 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5274 ("Dispatching %s event to %s (%p) and its ancestors",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5275 isPointer ? "ePointerLeave" : "eMouseLeave",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5276 wrapper->GetDeepestLeaveEventTarget()do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5277 ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str()do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5278 : "nullptr",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5279 wrapper->GetDeepestLeaveEventTarget()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
;
5280 leaveDispatcher.Dispatch();
5281
5282 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"out\" and/or \"leave\" events"
); } } while (0)
5283 ("Dispatched \"out\" and/or \"leave\" events"))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"out\" and/or \"leave\" events"
); } } while (0)
;
5284 wrapper->DidDispatchOutAndOrLeaveEvent();
5285}
5286
5287void EventStateManager::RecomputeMouseEnterStateForRemoteFrame(
5288 Element& aElement) {
5289 if (!mMouseEnterLeaveHelper ||
5290 mMouseEnterLeaveHelper->GetDeepestLeaveEventTarget() != &aElement) {
5291 return;
5292 }
5293
5294 if (BrowserParent* remote = BrowserParent::GetFrom(&aElement)) {
5295 remote->MouseEnterIntoWidget();
5296 }
5297}
5298
5299void EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
5300 nsIContent* aContent) {
5301 NS_ASSERTION(aContent, "Mouse must be over something")do { if (!(aContent)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Mouse must be over something"
, "aContent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5301); MOZ_PretendNoReturn(); } } while (0)
;
5302
5303 const bool isPointer = aMouseEvent->mClass == ePointerEventClass;
5304 LogModule* const logModule =
5305 isPointer ? sPointerBoundaryLog : sMouseBoundaryLog;
5306
5307 RefPtr<OverOutElementsWrapper> wrapper = GetWrapperByEventID(aMouseEvent);
5308
5309 // If we have next "out" event target and it's the new "over" target, we don't
5310 // need to dispatch "out" nor "enter" event.
5311 if (!wrapper || aContent == wrapper->GetOutEventTarget()) {
5312 return;
5313 }
5314
5315 // Before firing "over" and "enter" events, check for recursion
5316 if (wrapper->IsDispatchingOverEventOn(aContent)) {
5317 return;
5318 }
5319
5320 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOver: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5321 ("NotifyMouseOver: the source event is %s (IsReal()=%s)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOver: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5322 ToChar(aMouseEvent->mMessage),do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOver: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5323 aMouseEvent->IsReal() ? "true" : "false"))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOver: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
;
5324
5325 // Check to see if we're a subdocument and if so update the parent
5326 // document's ESM state to indicate that the mouse is over the
5327 // content associated with our subdocument.
5328 EnsureDocument(mPresContext);
5329 if (Document* parentDoc = mDocument->GetInProcessParentDocument()) {
5330 if (nsCOMPtr<nsIContent> docContent = mDocument->GetEmbedderElement()) {
5331 if (PresShell* parentPresShell = parentDoc->GetPresShell()) {
5332 RefPtr<EventStateManager> parentESM =
5333 parentPresShell->GetPresContext()->EventStateManager();
5334 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying parent EventStateManager (%p) of \"over\" "
"event...", parentESM.get()); } } while (0)
5335 ("Notifying parent EventStateManager (%p) of \"over\" "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying parent EventStateManager (%p) of \"over\" "
"event...", parentESM.get()); } } while (0)
5336 "event...",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying parent EventStateManager (%p) of \"over\" "
"event...", parentESM.get()); } } while (0)
5337 parentESM.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying parent EventStateManager (%p) of \"over\" "
"event...", parentESM.get()); } } while (0)
;
5338 parentESM->NotifyMouseOver(aMouseEvent, docContent);
5339 }
5340 }
5341 }
5342 // Firing the DOM event in the parent document could cause all kinds
5343 // of havoc. Reverify and take care.
5344 if (aContent == wrapper->GetOutEventTarget()) {
5345 return;
5346 }
5347
5348 // Remember the deepest leave event target as the related content for the
5349 // DispatchMouseOrPointerBoundaryEvent() call below, since NotifyMouseOut()
5350 // resets it, bug 298477.
5351 nsCOMPtr<nsIContent> deepestLeaveEventTarget =
5352 wrapper->GetDeepestLeaveEventTarget();
5353
5354 EnterLeaveDispatcher enterDispatcher(this, aContent, deepestLeaveEventTarget,
5355 aMouseEvent,
5356 isPointer ? ePointerEnter : eMouseEnter);
5357
5358 if (!isPointer) {
5359 SetContentState(aContent, ElementState::HOVER);
5360 }
5361
5362 NotifyMouseOut(aMouseEvent, aContent);
5363
5364 wrapper->WillDispatchOverAndEnterEvent(aContent);
5365
5366 // Fire mouseover
5367 // XXX If aContent has already been removed from the DOM tree, what should we
5368 // do? At least, dispatching `mouseover` on it is odd.
5369 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOver" : "eMoustOver", aContent ? ToString(*aContent
).c_str() : "nullptr", aContent); } } while (0)
5370 ("Dispatching %s event to %s (%p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOver" : "eMoustOver", aContent ? ToString(*aContent
).c_str() : "nullptr", aContent); } } while (0)
5371 isPointer ? "ePointerOver" : "eMoustOver",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOver" : "eMoustOver", aContent ? ToString(*aContent
).c_str() : "nullptr", aContent); } } while (0)
5372 aContent ? ToString(*aContent).c_str() : "nullptr", aContent))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOver" : "eMoustOver", aContent ? ToString(*aContent
).c_str() : "nullptr", aContent); } } while (0)
;
5373 nsCOMPtr<nsIWidget> targetWidget = DispatchMouseOrPointerBoundaryEvent(
5374 aMouseEvent, isPointer ? ePointerOver : eMouseOver, aContent,
5375 deepestLeaveEventTarget);
5376
5377 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerEnter" : "eMouseEnter", aContent ? ToString
(*aContent).c_str() : "nullptr", aContent); } } while (0)
5378 ("Dispatching %s event to %s (%p) and its ancestors",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerEnter" : "eMouseEnter", aContent ? ToString
(*aContent).c_str() : "nullptr", aContent); } } while (0)
5379 isPointer ? "ePointerEnter" : "eMouseEnter",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerEnter" : "eMouseEnter", aContent ? ToString
(*aContent).c_str() : "nullptr", aContent); } } while (0)
5380 aContent ? ToString(*aContent).c_str() : "nullptr", aContent))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerEnter" : "eMouseEnter", aContent ? ToString
(*aContent).c_str() : "nullptr", aContent); } } while (0)
;
5381 enterDispatcher.Dispatch();
5382
5383 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"over\" and \"enter\" events (the original \"over\" "
"event target was in the document %p, and now in %p)", aContent
->GetComposedDoc(), mDocument.get()); } } while (0)
5384 ("Dispatched \"over\" and \"enter\" events (the original \"over\" "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"over\" and \"enter\" events (the original \"over\" "
"event target was in the document %p, and now in %p)", aContent
->GetComposedDoc(), mDocument.get()); } } while (0)
5385 "event target was in the document %p, and now in %p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"over\" and \"enter\" events (the original \"over\" "
"event target was in the document %p, and now in %p)", aContent
->GetComposedDoc(), mDocument.get()); } } while (0)
5386 aContent->GetComposedDoc(), mDocument.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"over\" and \"enter\" events (the original \"over\" "
"event target was in the document %p, and now in %p)", aContent
->GetComposedDoc(), mDocument.get()); } } while (0)
;
5387 wrapper->DidDispatchOverAndEnterEvent(
5388 aContent->GetComposedDoc() == mDocument ? aContent : nullptr,
5389 targetWidget);
5390}
5391
5392// Returns the center point of the window's client area. This is
5393// in widget coordinates, i.e. relative to the widget's top-left
5394// corner, not in screen coordinates, the same units that UIEvent::
5395// refpoint is in. It may not be the exact center of the window if
5396// the platform requires rounding the coordinate.
5397static LayoutDeviceIntPoint GetWindowClientRectCenter(nsIWidget* aWidget) {
5398 NS_ENSURE_TRUE(aWidget, LayoutDeviceIntPoint(0, 0))do { if ((__builtin_expect(!!(!(aWidget)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aWidget" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5398); return LayoutDeviceIntPoint(0, 0); } } while (false)
;
5399
5400 LayoutDeviceIntRect rect = aWidget->GetClientBounds();
5401 LayoutDeviceIntPoint point(rect.width / 2, rect.height / 2);
5402 int32_t round = aWidget->RoundsWidgetCoordinatesTo();
5403 point.x = point.x / round * round;
5404 point.y = point.y / round * round;
5405 return point;
5406}
5407
5408void EventStateManager::GeneratePointerEnterExit(EventMessage aMessage,
5409 WidgetMouseEvent* aEvent) {
5410 WidgetPointerEvent pointerEvent(*aEvent);
5411 pointerEvent.mMessage = aMessage;
5412 GenerateMouseEnterExit(&pointerEvent);
5413}
5414
5415/* static */
5416void EventStateManager::UpdateLastRefPointOfMouseEvent(
5417 WidgetMouseEvent* aMouseEvent) {
5418 if (aMouseEvent->mMessage != eMouseMove &&
5419 aMouseEvent->mMessage != ePointerMove) {
5420 return;
5421 }
5422
5423 // Mouse movement is reported on the MouseEvent.movement{X,Y} fields.
5424 // Movement is calculated in UIEvent::GetMovementPoint() as:
5425 // previous_mousemove_mRefPoint - current_mousemove_mRefPoint.
5426 if (PointerLockManager::IsLocked() && aMouseEvent->mWidget) {
5427 // The pointer is locked. If the pointer is not located at the center of
5428 // the window, dispatch a synthetic mousemove to return the pointer there.
5429 // Doing this between "real" pointer moves gives the impression that the
5430 // (locked) pointer can continue moving and won't stop at the screen
5431 // boundary. We cancel the synthetic event so that we don't end up
5432 // dispatching the centering move event to content.
5433 aMouseEvent->mLastRefPoint =
5434 GetWindowClientRectCenter(aMouseEvent->mWidget);
5435
5436 } else if (sLastRefPoint == kInvalidRefPoint) {
5437 // We don't have a valid previous mousemove mRefPoint. This is either
5438 // the first move we've encountered, or the mouse has just re-entered
5439 // the application window. We should report (0,0) movement for this
5440 // case, so make the current and previous mRefPoints the same.
5441 aMouseEvent->mLastRefPoint = aMouseEvent->mRefPoint;
5442 } else {
5443 aMouseEvent->mLastRefPoint = sLastRefPoint;
5444 }
5445}
5446
5447/* static */
5448void EventStateManager::ResetPointerToWindowCenterWhilePointerLocked(
5449 WidgetMouseEvent* aMouseEvent) {
5450 MOZ_ASSERT(PointerLockManager::IsLocked())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(PointerLockManager::IsLocked())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(PointerLockManager::IsLocked
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("PointerLockManager::IsLocked()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5450); AnnotateMozCrashReason("MOZ_ASSERT" "(" "PointerLockManager::IsLocked()"
")"); do { *((volatile int*)__null) = 5450; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5451 if ((aMouseEvent->mMessage != eMouseMove &&
5452 aMouseEvent->mMessage != ePointerMove) ||
5453 !aMouseEvent->mWidget) {
5454 return;
5455 }
5456
5457 // We generate pointermove from mousemove event, so only synthesize native
5458 // mouse move and update sSynthCenteringPoint by mousemove event.
5459 bool updateSynthCenteringPoint = aMouseEvent->mMessage == eMouseMove;
5460
5461 // The pointer is locked. If the pointer is not located at the center of
5462 // the window, dispatch a synthetic mousemove to return the pointer there.
5463 // Doing this between "real" pointer moves gives the impression that the
5464 // (locked) pointer can continue moving and won't stop at the screen
5465 // boundary. We cancel the synthetic event so that we don't end up
5466 // dispatching the centering move event to content.
5467 LayoutDeviceIntPoint center = GetWindowClientRectCenter(aMouseEvent->mWidget);
5468
5469 if (aMouseEvent->mRefPoint != center && updateSynthCenteringPoint) {
5470 // Mouse move doesn't finish at the center of the window. Dispatch a
5471 // synthetic native mouse event to move the pointer back to the center
5472 // of the window, to faciliate more movement. But first, record that
5473 // we've dispatched a synthetic mouse movement, so we can cancel it
5474 // in the other branch here.
5475 sSynthCenteringPoint = center;
5476 // XXX Once we fix XXX comments in SetPointerLock about this API, we could
5477 // restrict that this API works only in the automation mode or in the
5478 // pointer locked situation.
5479 aMouseEvent->mWidget->SynthesizeNativeMouseMove(
5480 center + aMouseEvent->mWidget->WidgetToScreenOffset(), nullptr);
5481 } else if (aMouseEvent->mRefPoint == sSynthCenteringPoint) {
5482 // This is the "synthetic native" event we dispatched to re-center the
5483 // pointer. Cancel it so we don't expose the centering move to content.
5484 aMouseEvent->StopPropagation();
5485 // Clear sSynthCenteringPoint so we don't cancel other events
5486 // targeted at the center.
5487 if (updateSynthCenteringPoint) {
5488 sSynthCenteringPoint = kInvalidRefPoint;
5489 }
5490 }
5491}
5492
5493/* static */
5494void EventStateManager::UpdateLastPointerPosition(
5495 WidgetMouseEvent* aMouseEvent) {
5496 if (aMouseEvent->mMessage != eMouseMove) {
5497 return;
5498 }
5499 sLastRefPoint = aMouseEvent->mRefPoint;
5500}
5501
5502void EventStateManager::GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent) {
5503 EnsureDocument(mPresContext);
5504 if (!mDocument) return;
5505
5506 // Hold onto old target content through the event and reset after.
5507 nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
5508
5509 switch (aMouseEvent->mMessage) {
5510 case eMouseMove:
5511 case ePointerMove:
5512 case ePointerDown:
5513 case ePointerGotCapture: {
5514 // Get the target content target (mousemove target == mouseover target)
5515 nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
5516 if (!targetElement) {
5517 // We're always over the document root, even if we're only
5518 // over dead space in a page (whose frame is not associated with
5519 // any content) or in print preview dead space
5520 targetElement = mDocument->GetRootElement();
5521 }
5522 if (targetElement) {
5523 NotifyMouseOver(aMouseEvent, targetElement);
5524 }
5525 break;
5526 }
5527 case ePointerUp: {
5528 if (!StaticPrefs::
5529 dom_events_mouse_pointer_boundary_keep_enter_targets_after_over_target_removed()) {
5530 // In the legacy mode, we should do nothing if the event has not been
5531 // dispatched yet (i.e., called by PreHandleEvent).
5532 // On the other hand, if the event was dispatched (i.e., called by
5533 // PostEventHandler), we need to dispatch "pointerout" and
5534 // "pointerleave" events because the pointer will be removed
5535 // (invalidated) by the "pointerup" operation.
5536 if (!aMouseEvent->mFlags.mDispatchedAtLeastOnce) {
5537 break;
5538 }
5539 MOZ_ASSERT(!aMouseEvent->InputSourceSupportsHover())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aMouseEvent->InputSourceSupportsHover())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aMouseEvent->InputSourceSupportsHover()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aMouseEvent->InputSourceSupportsHover()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5539); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aMouseEvent->InputSourceSupportsHover()"
")"); do { *((volatile int*)__null) = 5539; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5540 // Get the target content target (pointermove target == pointerover
5541 // target)
5542 nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
5543 if (!targetElement) {
5544 // We're always over the document root, even if we're only
5545 // over dead space in a page (whose frame is not associated with
5546 // any content) or in print preview dead space
5547 targetElement = mDocument->GetRootElement();
5548 }
5549 if (targetElement) {
5550 // XXX It's odd to override the `pointerout` event target with the
5551 // content under the pointer or something because it may have never
5552 // received `pointerover` event. I think that this was required for
5553 // digitizer which supports hover state (bug 985511). However, this
5554 // is now not called at ePointerUp if the device supports hover.
5555 RefPtr<OverOutElementsWrapper> helper =
5556 GetWrapperByEventID(aMouseEvent);
5557 if (helper) {
5558 helper->OverrideOverEventTarget(targetElement);
5559 }
5560 NotifyMouseOut(aMouseEvent, nullptr);
5561 }
5562 break;
5563 }
5564
5565 if (aMouseEvent->mFlags.mDispatchedAtLeastOnce) {
5566 // If we've already dispatched the pointerup event caused by
5567 // non-hoverable input device like touch, we need to synthesize
5568 // pointerout and pointerleave events because the poiner is valid only
5569 // while it's "down".
5570 if (!aMouseEvent->InputSourceSupportsHover()) {
5571 NotifyMouseOut(aMouseEvent, nullptr);
5572 }
5573 break;
5574 }
5575
5576 // If we're going to dispatch the pointerup event and the element under
5577 // the pointer is changed from the previous pointer event dispatching, we
5578 // need to dispatch pointer boundary events. If the pointing device is
5579 // hoverable, we always need to do it. Otherwise, an element captures the
5580 // pointer by default. If so, we don't need the boundary events, but if
5581 // the capture has already been released, e.g., by the capturing element
5582 // is removed, we need to dispatch the pointer boundary event the same
5583 // way as with hoverable pointer.
5584 if (aMouseEvent->InputSourceSupportsHover() ||
5585 !PointerEventHandler::GetPointerCapturingElement(
5586 aMouseEvent->pointerId)) {
5587 nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
5588 if (!targetElement) {
5589 targetElement = mDocument->GetRootElement();
5590 }
5591 if (targetElement) {
5592 NotifyMouseOver(aMouseEvent, targetElement);
5593 }
5594 break;
5595 }
5596 break;
5597 }
5598 case ePointerLeave:
5599 case ePointerCancel:
5600 case eMouseExitFromWidget: {
5601 // This is actually the window mouse exit or pointer leave event. We're
5602 // not moving into any new element.
5603
5604 RefPtr<OverOutElementsWrapper> helper = GetWrapperByEventID(aMouseEvent);
5605 if (helper) {
5606 nsCOMPtr<nsIWidget> lastOverWidget = helper->GetLastOverWidget();
5607 if (lastOverWidget &&
5608 nsContentUtils::GetTopLevelWidget(aMouseEvent->mWidget) !=
5609 nsContentUtils::GetTopLevelWidget(lastOverWidget)) {
5610 // the Mouse/PointerOut event widget doesn't have same top widget with
5611 // the last over event target, it's a spurious event for the frame for
5612 // the target.
5613 break;
5614 }
5615 }
5616
5617 // Reset sLastRefPoint, so that we'll know not to report any
5618 // movement the next time we re-enter the window.
5619 sLastRefPoint = kInvalidRefPoint;
5620
5621 NotifyMouseOut(aMouseEvent, nullptr);
5622 break;
5623 }
5624 default:
5625 break;
5626 }
5627
5628 // reset mCurretTargetContent to what it was
5629 mCurrentTargetContent = targetBeforeEvent;
5630}
5631
5632OverOutElementsWrapper* EventStateManager::GetWrapperByEventID(
5633 WidgetMouseEvent* aEvent) {
5634 WidgetPointerEvent* pointer = aEvent->AsPointerEvent();
5635 if (!pointer) {
5636 MOZ_ASSERT(aEvent->AsMouseEvent() != nullptr)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->AsMouseEvent() != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->AsMouseEvent() !=
nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aEvent->AsMouseEvent() != nullptr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5636); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->AsMouseEvent() != nullptr"
")"); do { *((volatile int*)__null) = 5636; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5637 if (!mMouseEnterLeaveHelper) {
5638 mMouseEnterLeaveHelper = new OverOutElementsWrapper(
5639 OverOutElementsWrapper::BoundaryEventType::Mouse);
5640 }
5641 return mMouseEnterLeaveHelper;
5642 }
5643 return mPointersEnterLeaveHelper.GetOrInsertNew(
5644 pointer->pointerId, OverOutElementsWrapper::BoundaryEventType::Pointer);
5645}
5646
5647/* static */
5648void EventStateManager::SetPointerLock(nsIWidget* aWidget,
5649 nsPresContext* aPresContext) {
5650 // Reset mouse wheel transaction
5651 WheelTransaction::EndTransaction();
5652
5653 // Deal with DnD events
5654 nsCOMPtr<nsIDragService> dragService =
5655 do_GetService("@mozilla.org/widget/dragservice;1");
5656
5657 if (PointerLockManager::IsLocked()) {
5658 MOZ_ASSERT(aWidget, "Locking pointer requires a widget")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aWidget))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aWidget" " (" "Locking pointer requires a widget"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5658); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWidget" ") ("
"Locking pointer requires a widget" ")"); do { *((volatile int
*)__null) = 5658; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
5659 MOZ_ASSERT(aPresContext, "Locking pointer requires a presContext")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresContext))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPresContext" " ("
"Locking pointer requires a presContext" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5659); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresContext"
") (" "Locking pointer requires a presContext" ")"); do { *(
(volatile int*)__null) = 5659; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
5660
5661 // Release all pointer capture when a pointer lock is successfully applied
5662 // on an element.
5663 PointerEventHandler::ReleaseAllPointerCapture();
5664
5665 // Store the last known ref point so we can reposition the pointer after
5666 // unlock.
5667 sPreLockScreenPoint = LayoutDeviceIntPoint::Round(
5668 sLastScreenPoint * aPresContext->CSSToDevPixelScale());
5669
5670 // Fire a synthetic mouse move to ensure event state is updated. We first
5671 // set the mouse to the center of the window, so that the mouse event
5672 // doesn't report any movement.
5673 // XXX Cannot we do synthesize the native mousemove in the parent process
5674 // with calling LockNativePointer below? Then, we could make this API
5675 // work only in the automation mode.
5676 sLastRefPoint = GetWindowClientRectCenter(aWidget);
5677 aWidget->SynthesizeNativeMouseMove(
5678 sLastRefPoint + aWidget->WidgetToScreenOffset(), nullptr);
5679
5680 // Suppress DnD
5681 if (dragService) {
5682 dragService->Suppress();
5683 }
5684
5685 // Activate native pointer lock on platforms where it is required (Wayland)
5686 aWidget->LockNativePointer();
5687 } else {
5688 if (aWidget) {
5689 // Deactivate native pointer lock on platforms where it is required
5690 aWidget->UnlockNativePointer();
5691 }
5692
5693 // Reset SynthCenteringPoint to invalid so that next time we start
5694 // locking pointer, it has its initial value.
5695 sSynthCenteringPoint = kInvalidRefPoint;
5696 if (aWidget) {
5697 // Unlocking, so return pointer to the original position by firing a
5698 // synthetic mouse event. We first reset sLastRefPoint to its
5699 // pre-pointerlock position, so that the synthetic mouse event reports
5700 // no movement.
5701 sLastRefPoint = sPreLockScreenPoint - aWidget->WidgetToScreenOffset();
5702 // XXX Cannot we do synthesize the native mousemove in the parent process
5703 // with calling `UnlockNativePointer` above? Then, we could make this
5704 // API work only in the automation mode.
5705 aWidget->SynthesizeNativeMouseMove(sPreLockScreenPoint, nullptr);
5706 }
5707
5708 // Unsuppress DnD
5709 if (dragService) {
5710 dragService->Unsuppress();
5711 }
5712 }
5713}
5714
5715void EventStateManager::GenerateDragDropEnterExit(nsPresContext* aPresContext,
5716 WidgetDragEvent* aDragEvent) {
5717 // Hold onto old target content through the event and reset after.
5718 nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
5719
5720 switch (aDragEvent->mMessage) {
5721 case eDragOver: {
5722 // when dragging from one frame to another, events are fired in the
5723 // order: dragexit, dragenter, dragleave
5724 if (sLastDragOverFrame != mCurrentTarget) {
5725 // We'll need the content, too, to check if it changed separately from
5726 // the frames.
5727 nsCOMPtr<nsIContent> lastContent;
5728 nsCOMPtr<nsIContent> targetContent;
5729 mCurrentTarget->GetContentForEvent(aDragEvent,
5730 getter_AddRefs(targetContent));
5731 if (targetContent && targetContent->IsText()) {
5732 targetContent = targetContent->GetFlattenedTreeParent();
5733 }
5734
5735 if (sLastDragOverFrame) {
5736 // The frame has changed but the content may not have. Check before
5737 // dispatching to content
5738 sLastDragOverFrame->GetContentForEvent(aDragEvent,
5739 getter_AddRefs(lastContent));
5740 if (lastContent && lastContent->IsText()) {
5741 lastContent = lastContent->GetFlattenedTreeParent();
5742 }
5743
5744 RefPtr<nsPresContext> presContext = sLastDragOverFrame->PresContext();
5745 FireDragEnterOrExit(presContext, aDragEvent, eDragExit, targetContent,
5746 lastContent, sLastDragOverFrame);
5747 nsIContent* target = sLastDragOverFrame
5748 ? sLastDragOverFrame.GetFrame()->GetContent()
5749 : nullptr;
5750 // XXXedgar, look like we need to consider fission OOP iframe, too.
5751 if (IsTopLevelRemoteTarget(target)) {
5752 // Dragging something and moving from web content to chrome only
5753 // fires dragexit and dragleave to xul:browser. We have to forward
5754 // dragexit to sLastDragOverFrame when its content is a remote
5755 // target. We don't forward dragleave since it's generated from
5756 // dragexit.
5757 WidgetDragEvent remoteEvent(aDragEvent->IsTrusted(), eDragExit,
5758 aDragEvent->mWidget);
5759 remoteEvent.AssignDragEventData(*aDragEvent, true);
5760 remoteEvent.mFlags.mIsSynthesizedForTests =
5761 aDragEvent->mFlags.mIsSynthesizedForTests;
5762 nsEventStatus remoteStatus = nsEventStatus_eIgnore;
5763 HandleCrossProcessEvent(&remoteEvent, &remoteStatus);
5764 }
5765 }
5766
5767 AutoWeakFrame currentTraget = mCurrentTarget;
5768 FireDragEnterOrExit(aPresContext, aDragEvent, eDragEnter, lastContent,
5769 targetContent, currentTraget);
5770
5771 if (sLastDragOverFrame) {
5772 RefPtr<nsPresContext> presContext = sLastDragOverFrame->PresContext();
5773 FireDragEnterOrExit(presContext, aDragEvent, eDragLeave,
5774 targetContent, lastContent, sLastDragOverFrame);
5775 }
5776
5777 sLastDragOverFrame = mCurrentTarget;
5778 }
5779 } break;
5780
5781 case eDragExit: {
5782 // This is actually the window mouse exit event.
5783 if (sLastDragOverFrame) {
5784 nsCOMPtr<nsIContent> lastContent;
5785 sLastDragOverFrame->GetContentForEvent(aDragEvent,
5786 getter_AddRefs(lastContent));
5787
5788 RefPtr<nsPresContext> lastDragOverFramePresContext =
5789 sLastDragOverFrame->PresContext();
5790 FireDragEnterOrExit(lastDragOverFramePresContext, aDragEvent, eDragExit,
5791 nullptr, lastContent, sLastDragOverFrame);
5792 FireDragEnterOrExit(lastDragOverFramePresContext, aDragEvent,
5793 eDragLeave, nullptr, lastContent,
5794 sLastDragOverFrame);
5795
5796 sLastDragOverFrame = nullptr;
5797 }
5798 } break;
5799
5800 default:
5801 break;
5802 }
5803
5804 // reset mCurretTargetContent to what it was
5805 mCurrentTargetContent = targetBeforeEvent;
5806
5807 // Now flush all pending notifications, for better responsiveness.
5808 FlushLayout(aPresContext);
5809}
5810
5811void EventStateManager::FireDragEnterOrExit(nsPresContext* aPresContext,
5812 WidgetDragEvent* aDragEvent,
5813 EventMessage aMessage,
5814 nsIContent* aRelatedTarget,
5815 nsIContent* aTargetContent,
5816 AutoWeakFrame& aTargetFrame) {
5817 MOZ_ASSERT(aMessage == eDragLeave || aMessage == eDragExit ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eDragLeave || aMessage == eDragExit || aMessage
== eDragEnter)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aMessage == eDragLeave || aMessage
== eDragExit || aMessage == eDragEnter))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eDragLeave || aMessage == eDragExit || aMessage == eDragEnter"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5818); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eDragLeave || aMessage == eDragExit || aMessage == eDragEnter"
")"); do { *((volatile int*)__null) = 5818; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5818 aMessage == eDragEnter)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eDragLeave || aMessage == eDragExit || aMessage
== eDragEnter)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aMessage == eDragLeave || aMessage
== eDragExit || aMessage == eDragEnter))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eDragLeave || aMessage == eDragExit || aMessage == eDragEnter"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5818); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eDragLeave || aMessage == eDragExit || aMessage == eDragEnter"
")"); do { *((volatile int*)__null) = 5818; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5819 nsEventStatus status = nsEventStatus_eIgnore;
5820 WidgetDragEvent event(aDragEvent->IsTrusted(), aMessage, aDragEvent->mWidget);
5821 event.AssignDragEventData(*aDragEvent, false);
5822 event.mFlags.mIsSynthesizedForTests =
5823 aDragEvent->mFlags.mIsSynthesizedForTests;
5824 event.mRelatedTarget = aRelatedTarget;
5825 if (aMessage == eDragExit && !StaticPrefs::dom_event_dragexit_enabled()) {
5826 event.mFlags.mOnlyChromeDispatch = true;
5827 }
5828
5829 mCurrentTargetContent = aTargetContent;
5830
5831 if (aTargetContent != aRelatedTarget) {
5832 // XXX This event should still go somewhere!!
5833 if (aTargetContent) {
5834 EventDispatcher::Dispatch(aTargetContent, aPresContext, &event, nullptr,
5835 &status);
5836 }
5837
5838 // adjust the drag hover if the dragenter event was cancelled or this is a
5839 // drag exit
5840 if (status == nsEventStatus_eConsumeNoDefault || aMessage == eDragExit) {
5841 SetContentState((aMessage == eDragEnter) ? aTargetContent : nullptr,
5842 ElementState::DRAGOVER);
5843 }
5844
5845 // collect any changes to moz cursor settings stored in the event's
5846 // data transfer.
5847 UpdateDragDataTransfer(&event);
5848 }
5849
5850 // Finally dispatch the event to the frame
5851 if (aTargetFrame) {
5852 aTargetFrame->HandleEvent(aPresContext, &event, &status);
5853 }
5854}
5855
5856void EventStateManager::UpdateDragDataTransfer(WidgetDragEvent* dragEvent) {
5857 NS_ASSERTION(dragEvent, "drag event is null in UpdateDragDataTransfer!")do { if (!(dragEvent)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "drag event is null in UpdateDragDataTransfer!"
, "dragEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5857); MOZ_PretendNoReturn(); } } while (0)
;
5858 if (!dragEvent->mDataTransfer) {
5859 return;
5860 }
5861
5862 nsCOMPtr<nsIDragSession> dragSession =
5863 nsContentUtils::GetDragSession(mPresContext);
5864
5865 if (dragSession) {
5866 // the initial dataTransfer is the one from the dragstart event that
5867 // was set on the dragSession when the drag began.
5868 RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer();
5869 if (initialDataTransfer) {
5870 // retrieve the current moz cursor setting and save it.
5871 nsAutoString mozCursor;
5872 dragEvent->mDataTransfer->GetMozCursor(mozCursor);
5873 initialDataTransfer->SetMozCursor(mozCursor);
5874 }
5875 }
5876}
5877
5878nsresult EventStateManager::SetClickCount(WidgetMouseEvent* aEvent,
5879 nsEventStatus* aStatus,
5880 nsIContent* aOverrideClickTarget) {
5881 nsCOMPtr<nsIContent> mouseContent = aOverrideClickTarget;
5882 if (!mouseContent && mCurrentTarget) {
5883 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(mouseContent));
5884 }
5885 if (mouseContent && mouseContent->IsText()) {
5886 nsINode* parent = mouseContent->GetFlattenedTreeParentNode();
5887 if (parent && parent->IsContent()) {
5888 mouseContent = parent->AsContent();
5889 }
5890 }
5891
5892 LastMouseDownInfo& mouseDownInfo = GetLastMouseDownInfo(aEvent->mButton);
5893 if (aEvent->mMessage == eMouseDown) {
5894 mouseDownInfo.mLastMouseDownContent =
5895 !aEvent->mClickEventPrevented ? mouseContent : nullptr;
5896
5897 if (mouseDownInfo.mLastMouseDownContent) {
5898 if (HTMLInputElement* input = HTMLInputElement::FromNodeOrNull(
5899 mouseDownInfo.mLastMouseDownContent)) {
5900 mouseDownInfo.mLastMouseDownInputControlType =
5901 Some(input->ControlType());
5902 } else if (mouseDownInfo.mLastMouseDownContent
5903 ->IsInNativeAnonymousSubtree()) {
5904 if (HTMLInputElement* input = HTMLInputElement::FromNodeOrNull(
5905 mouseDownInfo.mLastMouseDownContent
5906 ->GetFlattenedTreeParent())) {
5907 mouseDownInfo.mLastMouseDownInputControlType =
5908 Some(input->ControlType());
5909 }
5910 }
5911 }
5912 } else {
5913 aEvent->mClickTarget =
5914 !aEvent->mClickEventPrevented
5915 ? GetCommonAncestorForMouseUp(
5916 mouseContent, mouseDownInfo.mLastMouseDownContent,
5917 mouseDownInfo.mLastMouseDownInputControlType)
5918 : nullptr;
5919 if (aEvent->mClickTarget) {
5920 aEvent->mClickCount = mouseDownInfo.mClickCount;
5921 mouseDownInfo.mClickCount = 0;
5922 } else {
5923 aEvent->mClickCount = 0;
5924 }
5925 mouseDownInfo.mLastMouseDownContent = nullptr;
5926 mouseDownInfo.mLastMouseDownInputControlType = Nothing();
5927 }
5928
5929 return NS_OK;
5930}
5931
5932// static
5933bool EventStateManager::EventCausesClickEvents(
5934 const WidgetMouseEvent& aMouseEvent) {
5935 if (NS_WARN_IF(aMouseEvent.mMessage != eMouseUp)NS_warn_if_impl(aMouseEvent.mMessage != eMouseUp, "aMouseEvent.mMessage != eMouseUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5935)
) {
5936 return false;
5937 }
5938 // If the mouseup event is synthesized event, we don't need to dispatch
5939 // click events.
5940 if (!aMouseEvent.IsReal()) {
5941 return false;
5942 }
5943 // If mouse is still over same element, clickcount will be > 1.
5944 // If it has moved it will be zero, so no click.
5945 if (!aMouseEvent.mClickCount || !aMouseEvent.mClickTarget) {
5946 return false;
5947 }
5948 // If click event was explicitly prevented, we shouldn't dispatch it.
5949 if (aMouseEvent.mClickEventPrevented) {
5950 return false;
5951 }
5952 // Check that the window isn't disabled before firing a click
5953 // (see bug 366544).
5954 return !(aMouseEvent.mWidget && !aMouseEvent.mWidget->IsEnabled());
5955}
5956
5957nsresult EventStateManager::InitAndDispatchClickEvent(
5958 WidgetMouseEvent* aMouseUpEvent, nsEventStatus* aStatus,
5959 EventMessage aMessage, PresShell* aPresShell, nsIContent* aMouseUpContent,
5960 AutoWeakFrame aCurrentTarget, bool aNoContentDispatch,
5961 nsIContent* aOverrideClickTarget) {
5962 MOZ_ASSERT(aMouseUpEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseUpEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseUpEvent))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aMouseUpEvent",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5962); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpEvent"
")"); do { *((volatile int*)__null) = 5962; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
16
Taking false branch
17
Loop condition is false. Exiting loop
5963 MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(EventCausesClickEvents(*aMouseUpEvent))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(EventCausesClickEvents(*aMouseUpEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("EventCausesClickEvents(*aMouseUpEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5963); AnnotateMozCrashReason("MOZ_ASSERT" "(" "EventCausesClickEvents(*aMouseUpEvent)"
")"); do { *((volatile int*)__null) = 5963; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
18
Taking false branch
19
Loop condition is false. Exiting loop
5964 MOZ_ASSERT(aMouseUpContent || aCurrentTarget || aOverrideClickTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseUpContent || aCurrentTarget || aOverrideClickTarget
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aMouseUpContent || aCurrentTarget || aOverrideClickTarget
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aMouseUpContent || aCurrentTarget || aOverrideClickTarget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5964); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpContent || aCurrentTarget || aOverrideClickTarget"
")"); do { *((volatile int*)__null) = 5964; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
20
Taking false branch
21
Loop condition is false. Exiting loop
5965
5966 Maybe<WidgetPointerEvent> pointerEvent;
5967 Maybe<WidgetMouseEvent> mouseEvent;
22
Calling defaulted default constructor for 'Maybe<mozilla::WidgetMouseEvent>'
33
Returning from default constructor for 'Maybe<mozilla::WidgetMouseEvent>'
5968 if (IsPointerEventMessage(aMessage)) {
34
Assuming the condition is true
35
Taking true branch
5969 pointerEvent.emplace(aMouseUpEvent->IsTrusted(), aMessage,
5970 aMouseUpEvent->mWidget);
5971 } else {
5972 mouseEvent.emplace(aMouseUpEvent->IsTrusted(), aMessage,
5973 aMouseUpEvent->mWidget, WidgetMouseEvent::eReal);
5974 }
5975
5976 WidgetMouseEvent& mouseOrPointerEvent =
5977 pointerEvent.isSome() ? pointerEvent.ref() : mouseEvent.ref();
36
'?' condition is true
5978
5979 mouseOrPointerEvent.mRefPoint = aMouseUpEvent->mRefPoint;
5980 mouseOrPointerEvent.mClickCount = aMouseUpEvent->mClickCount;
5981 mouseOrPointerEvent.mModifiers = aMouseUpEvent->mModifiers;
5982 mouseOrPointerEvent.mButtons = aMouseUpEvent->mButtons;
5983 mouseOrPointerEvent.mTimeStamp = aMouseUpEvent->mTimeStamp;
5984 mouseOrPointerEvent.mFlags.mOnlyChromeDispatch = aNoContentDispatch;
5985 mouseOrPointerEvent.mFlags.mNoContentDispatch = aNoContentDispatch;
5986 mouseOrPointerEvent.mButton = aMouseUpEvent->mButton;
5987 mouseOrPointerEvent.pointerId = aMouseUpEvent->pointerId;
5988 mouseOrPointerEvent.mInputSource = aMouseUpEvent->mInputSource;
5989 nsIContent* target = aMouseUpContent;
5990 nsIFrame* targetFrame = aCurrentTarget;
5991 if (aOverrideClickTarget) {
37
Assuming 'aOverrideClickTarget' is null
38
Taking false branch
5992 target = aOverrideClickTarget;
5993 targetFrame = aOverrideClickTarget->GetPrimaryFrame();
5994 }
5995
5996 if (!target->IsInComposedDoc()) {
39
Assuming the condition is true
40
Taking true branch
5997 return NS_OK;
41
Calling implicit destructor for 'Maybe<mozilla::WidgetMouseEvent>'
42
Calling '~MaybeStorage'
5998 }
5999
6000 // Use local event status for each click event dispatching since it'll be
6001 // cleared by EventStateManager::PreHandleEvent(). Therefore, dispatching
6002 // an event means that previous event status will be ignored.
6003 nsEventStatus status = nsEventStatus_eIgnore;
6004 nsresult rv = aPresShell->HandleEventWithTarget(
6005 &mouseOrPointerEvent, targetFrame, MOZ_KnownLive(target)(target), &status);
6006
6007 // Copy mMultipleActionsPrevented flag from a click event to the mouseup
6008 // event only when it's set to true. It may be set to true if an editor has
6009 // already handled it. This is important to avoid two or more default
6010 // actions handled here.
6011 aMouseUpEvent->mFlags.mMultipleActionsPrevented |=
6012 mouseOrPointerEvent.mFlags.mMultipleActionsPrevented;
6013 // If current status is nsEventStatus_eConsumeNoDefault, we don't need to
6014 // overwrite it.
6015 if (*aStatus == nsEventStatus_eConsumeNoDefault) {
6016 return rv;
6017 }
6018 // If new status is nsEventStatus_eConsumeNoDefault or
6019 // nsEventStatus_eConsumeDoDefault, use it.
6020 if (status == nsEventStatus_eConsumeNoDefault ||
6021 status == nsEventStatus_eConsumeDoDefault) {
6022 *aStatus = status;
6023 return rv;
6024 }
6025 // Otherwise, keep the original status.
6026 return rv;
6027}
6028
6029nsresult EventStateManager::PostHandleMouseUp(
6030 WidgetMouseEvent* aMouseUpEvent, nsEventStatus* aStatus,
6031 nsIContent* aOverrideClickTarget) {
6032 MOZ_ASSERT(aMouseUpEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseUpEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseUpEvent))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aMouseUpEvent",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6032); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpEvent"
")"); do { *((volatile int*)__null) = 6032; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6033 MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(EventCausesClickEvents(*aMouseUpEvent))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(EventCausesClickEvents(*aMouseUpEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("EventCausesClickEvents(*aMouseUpEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6033); AnnotateMozCrashReason("MOZ_ASSERT" "(" "EventCausesClickEvents(*aMouseUpEvent)"
")"); do { *((volatile int*)__null) = 6033; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6034 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6034); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 6034; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6035
6036 RefPtr<PresShell> presShell = mPresContext->GetPresShell();
6037 if (!presShell) {
6038 return NS_OK;
6039 }
6040
6041 nsCOMPtr<nsIContent> clickTarget =
6042 nsIContent::FromEventTargetOrNull(aMouseUpEvent->mClickTarget);
6043 NS_ENSURE_STATE(clickTarget)do { if ((__builtin_expect(!!(!(clickTarget)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "clickTarget" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6043); return NS_ERROR_UNEXPECTED; } } while (false)
;
6044
6045 // Fire click events if the event target is still available.
6046 // Note that do not include the eMouseUp event's status since we ignore it
6047 // for compatibility with the other browsers.
6048 nsEventStatus status = nsEventStatus_eIgnore;
6049 nsresult rv = DispatchClickEvents(presShell, aMouseUpEvent, &status,
6050 clickTarget, aOverrideClickTarget);
6051 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6051)
) {
6052 return rv;
6053 }
6054
6055 // Do not do anything if preceding click events are consumed.
6056 // Note that Chromium dispatches "paste" event and actually pates clipboard
6057 // text into focused editor even if the preceding click events are consumed.
6058 // However, this is different from our traditional behavior and does not
6059 // conform to DOM events. If we need to keep compatibility with Chromium,
6060 // we should change it later.
6061 if (status == nsEventStatus_eConsumeNoDefault) {
6062 *aStatus = nsEventStatus_eConsumeNoDefault;
6063 return NS_OK;
6064 }
6065
6066 // Handle middle click paste if it's enabled and the mouse button is middle.
6067 if (aMouseUpEvent->mButton != MouseButton::eMiddle ||
6068 !WidgetMouseEvent::IsMiddleClickPasteEnabled()) {
6069 return NS_OK;
6070 }
6071 DebugOnly<nsresult> rvIgnored =
6072 HandleMiddleClickPaste(presShell, aMouseUpEvent, &status, nullptr);
6073 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to paste for a middle click"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6074); } } while (false)
6074 "Failed to paste for a middle click")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to paste for a middle click"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6074); } } while (false)
;
6075
6076 // If new status is nsEventStatus_eConsumeNoDefault or
6077 // nsEventStatus_eConsumeDoDefault, use it.
6078 if (*aStatus != nsEventStatus_eConsumeNoDefault &&
6079 (status == nsEventStatus_eConsumeNoDefault ||
6080 status == nsEventStatus_eConsumeDoDefault)) {
6081 *aStatus = status;
6082 }
6083
6084 // Don't return error even if middle mouse paste fails since we haven't
6085 // handled it here.
6086 return NS_OK;
6087}
6088
6089nsresult EventStateManager::DispatchClickEvents(
6090 PresShell* aPresShell, WidgetMouseEvent* aMouseUpEvent,
6091 nsEventStatus* aStatus, nsIContent* aClickTarget,
6092 nsIContent* aOverrideClickTarget) {
6093 MOZ_ASSERT(aPresShell)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresShell)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresShell))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aPresShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6093); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresShell"
")"); do { *((volatile int*)__null) = 6093; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1
Assuming 'aPresShell' is non-null
2
Taking false branch
3
Loop condition is false. Exiting loop
6094 MOZ_ASSERT(aMouseUpEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseUpEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseUpEvent))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aMouseUpEvent",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6094); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpEvent"
")"); do { *((volatile int*)__null) = 6094; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4
Assuming 'aMouseUpEvent' is non-null
5
Taking false branch
6
Loop condition is false. Exiting loop
6095 MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(EventCausesClickEvents(*aMouseUpEvent))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(EventCausesClickEvents(*aMouseUpEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("EventCausesClickEvents(*aMouseUpEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6095); AnnotateMozCrashReason("MOZ_ASSERT" "(" "EventCausesClickEvents(*aMouseUpEvent)"
")"); do { *((volatile int*)__null) = 6095; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7
Taking false branch
8
Loop condition is false. Exiting loop
6096 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6096); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 6096; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9
Assuming 'aStatus' is non-null
10
Taking false branch
11
Loop condition is false. Exiting loop
6097 MOZ_ASSERT(aClickTarget || aOverrideClickTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aClickTarget || aOverrideClickTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aClickTarget || aOverrideClickTarget
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aClickTarget || aOverrideClickTarget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6097); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aClickTarget || aOverrideClickTarget"
")"); do { *((volatile int*)__null) = 6097; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
12
Assuming 'aClickTarget' is non-null
13
Taking false branch
6098
6099 bool notDispatchToContents =
6100 (aMouseUpEvent->mButton == MouseButton::eMiddle ||
14
Assuming field 'mButton' is equal to eMiddle
6101 aMouseUpEvent->mButton == MouseButton::eSecondary);
6102
6103 bool fireAuxClick = notDispatchToContents;
6104
6105 AutoWeakFrame currentTarget = aClickTarget->GetPrimaryFrame();
6106 nsresult rv = InitAndDispatchClickEvent(
15
Calling 'EventStateManager::InitAndDispatchClickEvent'
6107 aMouseUpEvent, aStatus, ePointerClick, aPresShell, aClickTarget,
6108 currentTarget, notDispatchToContents, aOverrideClickTarget);
6109 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6109)
) {
6110 return rv;
6111 }
6112
6113 // Fire auxclick event if necessary.
6114 if (fireAuxClick && *aStatus != nsEventStatus_eConsumeNoDefault &&
6115 aClickTarget && aClickTarget->IsInComposedDoc()) {
6116 rv = InitAndDispatchClickEvent(aMouseUpEvent, aStatus, ePointerAuxClick,
6117 aPresShell, aClickTarget, currentTarget,
6118 false, aOverrideClickTarget);
6119 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to dispatch ePointerAuxClick"
, "NS_SUCCEEDED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6120); } } while (false)
6120 "Failed to dispatch ePointerAuxClick")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to dispatch ePointerAuxClick"
, "NS_SUCCEEDED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6120); } } while (false)
;
6121 }
6122
6123 // Fire double click event if click count is 2.
6124 if (aMouseUpEvent->mClickCount == 2 && !fireAuxClick && aClickTarget &&
6125 aClickTarget->IsInComposedDoc()) {
6126 rv = InitAndDispatchClickEvent(aMouseUpEvent, aStatus, eMouseDoubleClick,
6127 aPresShell, aClickTarget, currentTarget,
6128 notDispatchToContents, aOverrideClickTarget);
6129 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6129)
) {
6130 return rv;
6131 }
6132 }
6133
6134 return rv;
6135}
6136
6137nsresult EventStateManager::HandleMiddleClickPaste(
6138 PresShell* aPresShell, WidgetMouseEvent* aMouseEvent,
6139 nsEventStatus* aStatus, EditorBase* aEditorBase) {
6140 MOZ_ASSERT(aPresShell)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresShell)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresShell))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aPresShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6140); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresShell"
")"); do { *((volatile int*)__null) = 6140; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6141 MOZ_ASSERT(aMouseEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseEvent))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aMouseEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6141); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseEvent"
")"); do { *((volatile int*)__null) = 6141; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6142 MOZ_ASSERT((aMouseEvent->mMessage == ePointerAuxClick &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aMouseEvent->mMessage == ePointerAuxClick &&
aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents
(*aMouseEvent))>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!((aMouseEvent->mMessage == ePointerAuxClick
&& aMouseEvent->mButton == MouseButton::eMiddle) ||
EventCausesClickEvents(*aMouseEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6144); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
")"); do { *((volatile int*)__null) = 6144; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6143 aMouseEvent->mButton == MouseButton::eMiddle) ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aMouseEvent->mMessage == ePointerAuxClick &&
aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents
(*aMouseEvent))>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!((aMouseEvent->mMessage == ePointerAuxClick
&& aMouseEvent->mButton == MouseButton::eMiddle) ||
EventCausesClickEvents(*aMouseEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6144); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
")"); do { *((volatile int*)__null) = 6144; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6144 EventCausesClickEvents(*aMouseEvent))do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aMouseEvent->mMessage == ePointerAuxClick &&
aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents
(*aMouseEvent))>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!((aMouseEvent->mMessage == ePointerAuxClick
&& aMouseEvent->mButton == MouseButton::eMiddle) ||
EventCausesClickEvents(*aMouseEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6144); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
")"); do { *((volatile int*)__null) = 6144; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6145 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6145); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 6145; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6146 MOZ_ASSERT(*aStatus != nsEventStatus_eConsumeNoDefault)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(*aStatus != nsEventStatus_eConsumeNoDefault))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6146); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault"
")"); do { *((volatile int*)__null) = 6146; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6147
6148 // Even if we're called twice or more for a mouse operation, we should
6149 // handle only once. Although mMultipleActionsPrevented may be set to
6150 // true by different event handler in the future, we can use it for now.
6151 if (aMouseEvent->mFlags.mMultipleActionsPrevented) {
6152 return NS_OK;
6153 }
6154 aMouseEvent->mFlags.mMultipleActionsPrevented = true;
6155
6156 RefPtr<Selection> selection;
6157 if (aEditorBase) {
6158 selection = aEditorBase->GetSelection();
6159 if (NS_WARN_IF(!selection)NS_warn_if_impl(!selection, "!selection", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6159)
) {
6160 return NS_ERROR_FAILURE;
6161 }
6162 } else {
6163 Document* document = aPresShell->GetDocument();
6164 if (NS_WARN_IF(!document)NS_warn_if_impl(!document, "!document", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6164)
) {
6165 return NS_ERROR_FAILURE;
6166 }
6167 selection = nsCopySupport::GetSelectionForCopy(document);
6168 if (NS_WARN_IF(!selection)NS_warn_if_impl(!selection, "!selection", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6168)
) {
6169 return NS_ERROR_FAILURE;
6170 }
6171
6172 const nsRange* range = selection->GetRangeAt(0);
6173 if (range) {
6174 nsINode* target = range->GetStartContainer();
6175 if (target && target->OwnerDoc()->IsInChromeDocShell()) {
6176 // In Chrome document, limit middle-click pasting to only the editor
6177 // because it looks odd if pasting works in the focused editor when you
6178 // middle-click toolbar or something which are far from the editor.
6179 // However, as DevTools especially Web Console module assumes that paste
6180 // event will be fired when middle-click even on not editor, don't limit
6181 // it.
6182 return NS_OK;
6183 }
6184 }
6185 }
6186
6187 // Don't modify selection here because we've already set caret to the point
6188 // at "mousedown" event.
6189
6190 nsIClipboard::ClipboardType clipboardType = nsIClipboard::kGlobalClipboard;
6191 nsCOMPtr<nsIClipboard> clipboardService =
6192 do_GetService("@mozilla.org/widget/clipboard;1");
6193 if (clipboardService && clipboardService->IsClipboardTypeSupported(
6194 nsIClipboard::kSelectionClipboard)) {
6195 clipboardType = nsIClipboard::kSelectionClipboard;
6196 }
6197
6198 // Fire ePaste event by ourselves since we need to dispatch "paste" event
6199 // even if the middle click event was consumed for compatibility with
6200 // Chromium.
6201 if (!nsCopySupport::FireClipboardEvent(ePaste, Some(clipboardType),
6202 aPresShell, selection)) {
6203 *aStatus = nsEventStatus_eConsumeNoDefault;
6204 return NS_OK;
6205 }
6206
6207 // Although we've fired "paste" event, there is no editor to accept the
6208 // clipboard content.
6209 if (!aEditorBase) {
6210 return NS_OK;
6211 }
6212
6213 // Check if the editor is still the good target to paste.
6214 if (aEditorBase->Destroyed() || aEditorBase->IsReadonly()) {
6215 // XXX Should we consume the event when the editor is readonly and/or
6216 // disabled?
6217 return NS_OK;
6218 }
6219
6220 // The selection may have been modified during reflow. Therefore, we
6221 // should adjust event target to pass IsAcceptableInputEvent().
6222 const nsRange* range = selection->GetRangeAt(0);
6223 if (!range) {
6224 return NS_OK;
6225 }
6226 WidgetMouseEvent mouseEvent(*aMouseEvent);
6227 mouseEvent.mOriginalTarget = range->GetStartContainer();
6228 if (NS_WARN_IF(!mouseEvent.mOriginalTarget)NS_warn_if_impl(!mouseEvent.mOriginalTarget, "!mouseEvent.mOriginalTarget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6228)
||
6229 !aEditorBase->IsAcceptableInputEvent(&mouseEvent)) {
6230 return NS_OK;
6231 }
6232
6233 // If Control key is pressed, we should paste clipboard content as
6234 // quotation. Otherwise, paste it as is.
6235 if (aMouseEvent->IsControl()) {
6236 DebugOnly<nsresult> rv = aEditorBase->PasteAsQuotationAsAction(
6237 clipboardType, EditorBase::DispatchPasteEvent::No);
6238 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to paste as quotation")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to paste as quotation"
, "NS_SUCCEEDED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6238); } } while (false)
;
6239 } else {
6240 DebugOnly<nsresult> rv = aEditorBase->PasteAsAction(
6241 clipboardType, EditorBase::DispatchPasteEvent::No);
6242 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to paste")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to paste", "NS_SUCCEEDED(rv)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6242); } } while (false)
;
6243 }
6244 *aStatus = nsEventStatus_eConsumeNoDefault;
6245
6246 return NS_OK;
6247}
6248
6249void EventStateManager::ConsumeInteractionData(
6250 Record<nsString, dom::InteractionData>& aInteractions) {
6251 OnTypingInteractionEnded();
6252
6253 aInteractions.Entries().Clear();
6254 auto newEntry = aInteractions.Entries().AppendElement();
6255 newEntry->mKey = u"Typing"_ns;
6256 newEntry->mValue = gTypingInteraction;
6257 gTypingInteraction = {};
6258}
6259
6260nsIFrame* EventStateManager::GetEventTarget() {
6261 PresShell* presShell;
6262 if (mCurrentTarget || !mPresContext ||
6263 !(presShell = mPresContext->GetPresShell())) {
6264 return mCurrentTarget;
6265 }
6266
6267 if (mCurrentTargetContent) {
6268 mCurrentTarget = mPresContext->GetPrimaryFrameFor(mCurrentTargetContent);
6269 if (mCurrentTarget) {
6270 return mCurrentTarget;
6271 }
6272 }
6273
6274 nsIFrame* frame = presShell->GetCurrentEventFrame();
6275 return (mCurrentTarget = frame);
6276}
6277
6278already_AddRefed<nsIContent> EventStateManager::GetEventTargetContent(
6279 WidgetEvent* aEvent) {
6280 if (aEvent && (aEvent->mMessage == eFocus || aEvent->mMessage == eBlur)) {
6281 nsCOMPtr<nsIContent> content = GetFocusedElement();
6282 return content.forget();
6283 }
6284
6285 if (mCurrentTargetContent) {
6286 nsCOMPtr<nsIContent> content = mCurrentTargetContent;
6287 return content.forget();
6288 }
6289
6290 nsCOMPtr<nsIContent> content;
6291 if (PresShell* presShell = mPresContext->GetPresShell()) {
6292 content = presShell->GetEventTargetContent(aEvent);
6293 }
6294
6295 // Some events here may set mCurrentTarget but not set the corresponding
6296 // event target in the PresShell.
6297 if (!content && mCurrentTarget) {
6298 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(content));
6299 }
6300
6301 return content.forget();
6302}
6303
6304static Element* GetLabelTarget(nsIContent* aPossibleLabel) {
6305 mozilla::dom::HTMLLabelElement* label =
6306 mozilla::dom::HTMLLabelElement::FromNode(aPossibleLabel);
6307 if (!label) return nullptr;
6308
6309 return label->GetLabeledElement();
6310}
6311
6312/* static */
6313inline void EventStateManager::DoStateChange(Element* aElement,
6314 ElementState aState,
6315 bool aAddState) {
6316 if (aAddState) {
6317 aElement->AddStates(aState);
6318 } else {
6319 aElement->RemoveStates(aState);
6320 }
6321}
6322
6323/* static */
6324inline void EventStateManager::DoStateChange(nsIContent* aContent,
6325 ElementState aState,
6326 bool aStateAdded) {
6327 if (aContent->IsElement()) {
6328 DoStateChange(aContent->AsElement(), aState, aStateAdded);
6329 }
6330}
6331
6332/* static */
6333void EventStateManager::UpdateAncestorState(nsIContent* aStartNode,
6334 nsIContent* aStopBefore,
6335 ElementState aState,
6336 bool aAddState) {
6337 for (; aStartNode && aStartNode != aStopBefore;
6338 aStartNode = aStartNode->GetFlattenedTreeParent()) {
6339 // We might be starting with a non-element (e.g. a text node) and
6340 // if someone is doing something weird might be ending with a
6341 // non-element too (e.g. a document fragment)
6342 if (!aStartNode->IsElement()) {
6343 continue;
6344 }
6345 Element* element = aStartNode->AsElement();
6346 DoStateChange(element, aState, aAddState);
6347 Element* labelTarget = GetLabelTarget(element);
6348 if (labelTarget) {
6349 DoStateChange(labelTarget, aState, aAddState);
6350 }
6351 }
6352
6353 if (aAddState) {
6354 // We might be in a situation where a node was in hover both
6355 // because it was hovered and because the label for it was
6356 // hovered, and while we stopped hovering the node the label is
6357 // still hovered. Or we might have had two nested labels for the
6358 // same node, and while one is no longer hovered the other still
6359 // is. In that situation, the label that's still hovered will be
6360 // aStopBefore or some ancestor of it, and the call we just made
6361 // to UpdateAncestorState with aAddState = false would have
6362 // removed the hover state from the node. But the node should
6363 // still be in hover state. To handle this situation we need to
6364 // keep walking up the tree and any time we find a label mark its
6365 // corresponding node as still in our state.
6366 for (; aStartNode; aStartNode = aStartNode->GetFlattenedTreeParent()) {
6367 if (!aStartNode->IsElement()) {
6368 continue;
6369 }
6370
6371 Element* labelTarget = GetLabelTarget(aStartNode->AsElement());
6372 if (labelTarget && !labelTarget->State().HasState(aState)) {
6373 DoStateChange(labelTarget, aState, true);
6374 }
6375 }
6376 }
6377}
6378
6379// static
6380bool CanContentHaveActiveState(nsIContent& aContent) {
6381 // Editable content can never become active since their default actions
6382 // are disabled. Watch out for editable content in native anonymous
6383 // subtrees though, as they belong to text controls.
6384 return !aContent.IsEditable() || aContent.IsInNativeAnonymousSubtree();
6385}
6386
6387bool EventStateManager::SetContentState(nsIContent* aContent,
6388 ElementState aState) {
6389 MOZ_ASSERT(ManagesState(aState), "Unexpected state")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ManagesState(aState))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ManagesState(aState)))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("ManagesState(aState)"
" (" "Unexpected state" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6389); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ManagesState(aState)"
") (" "Unexpected state" ")"); do { *((volatile int*)__null)
= 6389; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
6390
6391 nsCOMPtr<nsIContent> notifyContent1;
6392 nsCOMPtr<nsIContent> notifyContent2;
6393 bool updateAncestors;
6394
6395 if (aState == ElementState::HOVER || aState == ElementState::ACTIVE) {
6396 // Hover and active are hierarchical
6397 updateAncestors = true;
6398
6399 // check to see that this state is allowed by style. Check dragover too?
6400 // XXX Is this even what we want?
6401 if (mCurrentTarget &&
6402 mCurrentTarget->StyleUI()->UserInput() == StyleUserInput::None) {
6403 return false;
6404 }
6405
6406 if (aState == ElementState::ACTIVE) {
6407 if (aContent && !CanContentHaveActiveState(*aContent)) {
6408 aContent = nullptr;
6409 }
6410 if (aContent != mActiveContent) {
6411 notifyContent1 = aContent;
6412 notifyContent2 = mActiveContent;
6413 mActiveContent = aContent;
6414 }
6415 } else {
6416 NS_ASSERTION(aState == ElementState::HOVER, "How did that happen?")do { if (!(aState == ElementState::HOVER)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "How did that happen?", "aState == ElementState::HOVER", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6416); MOZ_PretendNoReturn(); } } while (0)
;
6417 nsIContent* newHover;
6418
6419 if (mPresContext->IsDynamic()) {
6420 newHover = aContent;
6421 } else {
6422 NS_ASSERTION(!aContent || aContent->GetComposedDoc() ==do { if (!(!aContent || aContent->GetComposedDoc() == mPresContext
->PresShell()->GetDocument())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected document", "!aContent || aContent->GetComposedDoc() == mPresContext->PresShell()->GetDocument()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6424); MOZ_PretendNoReturn(); } } while (0)
6423 mPresContext->PresShell()->GetDocument(),do { if (!(!aContent || aContent->GetComposedDoc() == mPresContext
->PresShell()->GetDocument())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected document", "!aContent || aContent->GetComposedDoc() == mPresContext->PresShell()->GetDocument()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6424); MOZ_PretendNoReturn(); } } while (0)
6424 "Unexpected document")do { if (!(!aContent || aContent->GetComposedDoc() == mPresContext
->PresShell()->GetDocument())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected document", "!aContent || aContent->GetComposedDoc() == mPresContext->PresShell()->GetDocument()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6424); MOZ_PretendNoReturn(); } } while (0)
;
6425 nsIFrame* frame = aContent ? aContent->GetPrimaryFrame() : nullptr;
6426 if (frame && nsLayoutUtils::IsViewportScrollbarFrame(frame)) {
6427 // The scrollbars of viewport should not ignore the hover state.
6428 // Because they are *not* the content of the web page.
6429 newHover = aContent;
6430 } else {
6431 // All contents of the web page should ignore the hover state.
6432 newHover = nullptr;
6433 }
6434 }
6435
6436 if (newHover != mHoverContent) {
6437 notifyContent1 = newHover;
6438 notifyContent2 = mHoverContent;
6439 mHoverContent = newHover;
6440 }
6441 }
6442 } else {
6443 updateAncestors = false;
6444 if (aState == ElementState::DRAGOVER) {
6445 if (aContent != sDragOverContent) {
6446 notifyContent1 = aContent;
6447 notifyContent2 = sDragOverContent;
6448 sDragOverContent = aContent;
6449 }
6450 } else if (aState == ElementState::URLTARGET) {
6451 if (aContent != mURLTargetContent) {
6452 notifyContent1 = aContent;
6453 notifyContent2 = mURLTargetContent;
6454 mURLTargetContent = aContent;
6455 }
6456 }
6457 }
6458
6459 // We need to keep track of which of notifyContent1 and notifyContent2 is
6460 // getting the state set and which is getting it unset. If both are
6461 // non-null, then notifyContent1 is having the state set and notifyContent2
6462 // is having it unset. But if one of them is null, we need to keep track of
6463 // the right thing for notifyContent1 explicitly.
6464 bool content1StateSet = true;
6465 if (!notifyContent1) {
6466 // This is ok because FindCommonAncestor wouldn't find anything
6467 // anyway if notifyContent1 is null.
6468 notifyContent1 = notifyContent2;
6469 notifyContent2 = nullptr;
6470 content1StateSet = false;
6471 }
6472
6473 if (notifyContent1 && mPresContext) {
6474 EnsureDocument(mPresContext);
6475 if (mDocument) {
6476 nsAutoScriptBlocker scriptBlocker;
6477
6478 if (updateAncestors) {
6479 nsCOMPtr<nsIContent> commonAncestor =
6480 FindCommonAncestor(notifyContent1, notifyContent2);
6481 if (notifyContent2) {
6482 // It's very important to first notify the state removal and
6483 // then the state addition, because due to labels it's
6484 // possible that we're removing state from some element but
6485 // then adding it again (say because mHoverContent changed
6486 // from a control to its label).
6487 UpdateAncestorState(notifyContent2, commonAncestor, aState, false);
6488 }
6489 UpdateAncestorState(notifyContent1, commonAncestor, aState,
6490 content1StateSet);
6491 } else {
6492 if (notifyContent2) {
6493 DoStateChange(notifyContent2, aState, false);
6494 }
6495 DoStateChange(notifyContent1, aState, content1StateSet);
6496 }
6497 }
6498 }
6499
6500 return true;
6501}
6502
6503void EventStateManager::RemoveNodeFromChainIfNeeded(ElementState aState,
6504 nsIContent* aContentRemoved,
6505 bool aNotify) {
6506 MOZ_ASSERT(aState == ElementState::HOVER || aState == ElementState::ACTIVE)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aState == ElementState::HOVER || aState == ElementState
::ACTIVE)>::isValid, "invalid assertion condition"); if ((
__builtin_expect(!!(!(!!(aState == ElementState::HOVER || aState
== ElementState::ACTIVE))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aState == ElementState::HOVER || aState == ElementState::ACTIVE"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6506); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aState == ElementState::HOVER || aState == ElementState::ACTIVE"
")"); do { *((volatile int*)__null) = 6506; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6507 if (!aContentRemoved->IsElement() ||
6508 !aContentRemoved->AsElement()->State().HasState(aState)) {
6509 return;
6510 }
6511
6512 nsCOMPtr<nsIContent>& leaf =
6513 aState == ElementState::HOVER ? mHoverContent : mActiveContent;
6514
6515 MOZ_ASSERT(leaf)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(leaf)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(leaf))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("leaf", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6515); AnnotateMozCrashReason("MOZ_ASSERT" "(" "leaf" ")");
do { *((volatile int*)__null) = 6515; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6516 // These two NS_ASSERTIONS below can fail for Shadow DOM sometimes, and it's
6517 // not clear how to best handle it, see
6518 // https://github.com/whatwg/html/issues/4795 and bug 1551621.
6519 NS_ASSERTION(do { if (!(nsContentUtils::ContentIsFlattenedTreeDescendantOf
(leaf, aContentRemoved))) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"Flat tree and active / hover chain got out of sync", "nsContentUtils::ContentIsFlattenedTreeDescendantOf(leaf, aContentRemoved)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6521); MOZ_PretendNoReturn(); } } while (0)
6520 nsContentUtils::ContentIsFlattenedTreeDescendantOf(leaf, aContentRemoved),do { if (!(nsContentUtils::ContentIsFlattenedTreeDescendantOf
(leaf, aContentRemoved))) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"Flat tree and active / hover chain got out of sync", "nsContentUtils::ContentIsFlattenedTreeDescendantOf(leaf, aContentRemoved)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6521); MOZ_PretendNoReturn(); } } while (0)
6521 "Flat tree and active / hover chain got out of sync")do { if (!(nsContentUtils::ContentIsFlattenedTreeDescendantOf
(leaf, aContentRemoved))) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"Flat tree and active / hover chain got out of sync", "nsContentUtils::ContentIsFlattenedTreeDescendantOf(leaf, aContentRemoved)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6521); MOZ_PretendNoReturn(); } } while (0)
;
6522
6523 nsIContent* newLeaf = aContentRemoved->GetFlattenedTreeParent();
6524 MOZ_ASSERT(!newLeaf || newLeaf->IsElement())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!newLeaf || newLeaf->IsElement())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!newLeaf || newLeaf->IsElement
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!newLeaf || newLeaf->IsElement()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6524); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!newLeaf || newLeaf->IsElement()"
")"); do { *((volatile int*)__null) = 6524; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6525 NS_ASSERTION(!newLeaf || newLeaf->AsElement()->State().HasState(aState),do { if (!(!newLeaf || newLeaf->AsElement()->State().HasState
(aState))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "State got out of sync because of shadow DOM"
, "!newLeaf || newLeaf->AsElement()->State().HasState(aState)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6526); MOZ_PretendNoReturn(); } } while (0)
6526 "State got out of sync because of shadow DOM")do { if (!(!newLeaf || newLeaf->AsElement()->State().HasState
(aState))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "State got out of sync because of shadow DOM"
, "!newLeaf || newLeaf->AsElement()->State().HasState(aState)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6526); MOZ_PretendNoReturn(); } } while (0)
;
6527 if (aNotify) {
6528 SetContentState(newLeaf, aState);
6529 } else {
6530 // We don't update the removed content's state here, since removing NAC
6531 // happens from layout and we don't really want to notify at that point or
6532 // what not.
6533 //
6534 // Also, NAC is not observable and NAC being removed will go away soon.
6535 leaf = newLeaf;
6536 }
6537 MOZ_ASSERT(leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(leaf == newLeaf || (aState == ElementState::ACTIVE &&
!leaf && !CanContentHaveActiveState(*newLeaf)))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(leaf == newLeaf || (aState == ElementState::ACTIVE &&
!leaf && !CanContentHaveActiveState(*newLeaf))))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf && !CanContentHaveActiveState(*newLeaf))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6538); AnnotateMozCrashReason("MOZ_ASSERT" "(" "leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf && !CanContentHaveActiveState(*newLeaf))"
")"); do { *((volatile int*)__null) = 6538; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6538 !CanContentHaveActiveState(*newLeaf)))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(leaf == newLeaf || (aState == ElementState::ACTIVE &&
!leaf && !CanContentHaveActiveState(*newLeaf)))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(leaf == newLeaf || (aState == ElementState::ACTIVE &&
!leaf && !CanContentHaveActiveState(*newLeaf))))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf && !CanContentHaveActiveState(*newLeaf))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6538); AnnotateMozCrashReason("MOZ_ASSERT" "(" "leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf && !CanContentHaveActiveState(*newLeaf))"
")"); do { *((volatile int*)__null) = 6538; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6539}
6540
6541void EventStateManager::NativeAnonymousContentRemoved(nsIContent* aContent) {
6542 MOZ_ASSERT(aContent->IsRootOfNativeAnonymousSubtree())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContent->IsRootOfNativeAnonymousSubtree())>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aContent->IsRootOfNativeAnonymousSubtree()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aContent->IsRootOfNativeAnonymousSubtree()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6542); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsRootOfNativeAnonymousSubtree()"
")"); do { *((volatile int*)__null) = 6542; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6543 RemoveNodeFromChainIfNeeded(ElementState::HOVER, aContent, false);
6544 RemoveNodeFromChainIfNeeded(ElementState::ACTIVE, aContent, false);
6545
6546 nsCOMPtr<nsIContent>& lastLeftMouseDownContent =
6547 mLastLeftMouseDownInfo.mLastMouseDownContent;
6548 if (lastLeftMouseDownContent &&
6549 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
6550 lastLeftMouseDownContent, aContent)) {
6551 lastLeftMouseDownContent = aContent->GetFlattenedTreeParent();
6552 }
6553
6554 nsCOMPtr<nsIContent>& lastMiddleMouseDownContent =
6555 mLastMiddleMouseDownInfo.mLastMouseDownContent;
6556 if (lastMiddleMouseDownContent &&
6557 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
6558 lastMiddleMouseDownContent, aContent)) {
6559 lastMiddleMouseDownContent = aContent->GetFlattenedTreeParent();
6560 }
6561
6562 nsCOMPtr<nsIContent>& lastRightMouseDownContent =
6563 mLastRightMouseDownInfo.mLastMouseDownContent;
6564 if (lastRightMouseDownContent &&
6565 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
6566 lastRightMouseDownContent, aContent)) {
6567 lastRightMouseDownContent = aContent->GetFlattenedTreeParent();
6568 }
6569}
6570
6571void EventStateManager::ContentRemoved(Document* aDocument,
6572 nsIContent* aContent) {
6573 /*
6574 * Anchor and area elements when focused or hovered might make the UI to show
6575 * the current link. We want to make sure that the UI gets informed when they
6576 * are actually removed from the DOM.
6577 */
6578 if (aContent->IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area) &&
6579 (aContent->AsElement()->State().HasAtLeastOneOfStates(
6580 ElementState::FOCUS | ElementState::HOVER))) {
6581 Element* element = aContent->AsElement();
6582 element->LeaveLink(element->GetPresContext(Element::eForComposedDoc));
6583 }
6584
6585 if (aContent->IsElement()) {
6586 if (RefPtr<nsPresContext> presContext = mPresContext) {
6587 IMEStateManager::OnRemoveContent(*presContext,
6588 MOZ_KnownLive(*aContent->AsElement())(*aContent->AsElement()));
6589 }
6590 WheelTransaction::OnRemoveElement(aContent);
6591 }
6592
6593 // inform the focus manager that the content is being removed. If this
6594 // content is focused, the focus will be removed without firing events.
6595 if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
6596 fm->ContentRemoved(aDocument, aContent);
6597 }
6598
6599 RemoveNodeFromChainIfNeeded(ElementState::HOVER, aContent, true);
6600 RemoveNodeFromChainIfNeeded(ElementState::ACTIVE, aContent, true);
6601
6602 if (sDragOverContent &&
6603 sDragOverContent->OwnerDoc() == aContent->OwnerDoc() &&
6604 nsContentUtils::ContentIsFlattenedTreeDescendantOf(sDragOverContent,
6605 aContent)) {
6606 sDragOverContent = nullptr;
6607 }
6608
6609 PointerEventHandler::ReleaseIfCaptureByDescendant(aContent);
6610
6611 if (mMouseEnterLeaveHelper) {
6612 const bool hadMouseOutTarget =
6613 mMouseEnterLeaveHelper->GetOutEventTarget() != nullptr;
6614 mMouseEnterLeaveHelper->ContentRemoved(*aContent);
6615 // If we lose the mouseout target, we need to dispatch mouseover on an
6616 // ancestor. For ensuring the chance to do it before next user input, we
6617 // need a synthetic mouse move.
6618 if (hadMouseOutTarget && !mMouseEnterLeaveHelper->GetOutEventTarget()) {
6619 if (PresShell* presShell =
6620 mPresContext ? mPresContext->GetPresShell() : nullptr) {
6621 presShell->SynthesizeMouseMove(false);
6622 }
6623 }
6624 }
6625 for (const auto& entry : mPointersEnterLeaveHelper) {
6626 if (entry.GetData()) {
6627 entry.GetData()->ContentRemoved(*aContent);
6628 }
6629 }
6630}
6631
6632void EventStateManager::TextControlRootWillBeRemoved(
6633 TextControlElement& aTextControlElement) {
6634 if (!mGestureDownInTextControl || !mGestureDownFrameOwner ||
6635 !mGestureDownFrameOwner->IsInNativeAnonymousSubtree()) {
6636 return;
6637 }
6638 // If we track gesture to start drag in aTextControlElement, we should keep
6639 // tracking it with aTextContrlElement itself for now because this may be
6640 // caused by reframing aTextControlElement which may not be intended by the
6641 // user.
6642 if (&aTextControlElement ==
6643 mGestureDownFrameOwner
6644 ->GetClosestNativeAnonymousSubtreeRootParentOrHost()) {
6645 mGestureDownFrameOwner = &aTextControlElement;
6646 }
6647}
6648
6649void EventStateManager::TextControlRootAdded(
6650 Element& aAnonymousDivElement, TextControlElement& aTextControlElement) {
6651 if (!mGestureDownInTextControl ||
6652 mGestureDownFrameOwner != &aTextControlElement) {
6653 return;
6654 }
6655 // If we track gesture to start drag in aTextControlElement, but the frame
6656 // owner is the text control element itself, the anonymous nodes in it are
6657 // recreated by a reframe. If so, we should keep tracking it with the
6658 // recreated native anonymous node.
6659 mGestureDownFrameOwner =
6660 aAnonymousDivElement.GetFirstChild()
6661 ? aAnonymousDivElement.GetFirstChild()
6662 : static_cast<nsIContent*>(&aAnonymousDivElement);
6663}
6664
6665bool EventStateManager::EventStatusOK(WidgetGUIEvent* aEvent) {
6666 return !(aEvent->mMessage == eMouseDown &&
6667 aEvent->AsMouseEvent()->mButton == MouseButton::ePrimary &&
6668 !sNormalLMouseEventInProcess);
6669}
6670
6671//-------------------------------------------
6672// Access Key Registration
6673//-------------------------------------------
6674void EventStateManager::RegisterAccessKey(Element* aElement, uint32_t aKey) {
6675 if (aElement && !mAccessKeys.Contains(aElement)) {
6676 mAccessKeys.AppendObject(aElement);
6677 }
6678}
6679
6680void EventStateManager::UnregisterAccessKey(Element* aElement, uint32_t aKey) {
6681 if (aElement) {
6682 mAccessKeys.RemoveObject(aElement);
6683 }
6684}
6685
6686uint32_t EventStateManager::GetRegisteredAccessKey(Element* aElement) {
6687 MOZ_ASSERT(aElement)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aElement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aElement))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aElement", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6687); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aElement" ")"
); do { *((volatile int*)__null) = 6687; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6688
6689 if (!mAccessKeys.Contains(aElement)) {
6690 return 0;
6691 }
6692
6693 nsAutoString accessKey;
6694 aElement->GetAttr(nsGkAtoms::accesskey, accessKey);
6695 return accessKey.First();
6696}
6697
6698void EventStateManager::EnsureDocument(nsPresContext* aPresContext) {
6699 if (!mDocument) mDocument = aPresContext->Document();
6700}
6701
6702void EventStateManager::FlushLayout(nsPresContext* aPresContext) {
6703 MOZ_ASSERT(aPresContext, "nullptr ptr")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresContext))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPresContext" " ("
"nullptr ptr" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6703); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresContext"
") (" "nullptr ptr" ")"); do { *((volatile int*)__null) = 6703
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
6704 if (RefPtr<PresShell> presShell = aPresContext->GetPresShell()) {
6705 presShell->FlushPendingNotifications(FlushType::InterruptibleLayout);
6706 }
6707}
6708
6709Element* EventStateManager::GetFocusedElement() {
6710 nsFocusManager* fm = nsFocusManager::GetFocusManager();
6711 EnsureDocument(mPresContext);
6712 if (!fm || !mDocument) {
6713 return nullptr;
6714 }
6715
6716 nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
6717 return nsFocusManager::GetFocusedDescendant(
6718 mDocument->GetWindow(), nsFocusManager::eOnlyCurrentWindow,
6719 getter_AddRefs(focusedWindow));
6720}
6721
6722//-------------------------------------------------------
6723// Return true if the docshell is visible
6724
6725bool EventStateManager::IsShellVisible(nsIDocShell* aShell) {
6726 NS_ASSERTION(aShell, "docshell is null")do { if (!(aShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "docshell is null"
, "aShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6726); MOZ_PretendNoReturn(); } } while (0)
;
6727
6728 nsCOMPtr<nsIBaseWindow> basewin = do_QueryInterface(aShell);
6729 if (!basewin) return true;
6730
6731 bool isVisible = true;
6732 basewin->GetVisibility(&isVisible);
6733
6734 // We should be doing some additional checks here so that
6735 // we don't tab into hidden tabs of tabbrowser. -bryner
6736
6737 return isVisible;
6738}
6739
6740nsresult EventStateManager::DoContentCommandEvent(
6741 WidgetContentCommandEvent* aEvent) {
6742 EnsureDocument(mPresContext);
6743 NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(mDocument)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mDocument" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6743); return NS_ERROR_FAILURE; } } while (false)
;
6744 nsCOMPtr<nsPIDOMWindowOuter> window(mDocument->GetWindow());
6745 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(window)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "window" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6745); return NS_ERROR_FAILURE; } } while (false)
;
6746
6747 nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
6748 NS_ENSURE_TRUE(root, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(root)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "root" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6748); return NS_ERROR_FAILURE; } } while (false)
;
6749 const char* cmd;
6750 bool maybeNeedToHandleInRemote = false;
6751 switch (aEvent->mMessage) {
6752 case eContentCommandCut:
6753 cmd = "cmd_cut";
6754 maybeNeedToHandleInRemote = true;
6755 break;
6756 case eContentCommandCopy:
6757 cmd = "cmd_copy";
6758 maybeNeedToHandleInRemote = true;
6759 break;
6760 case eContentCommandPaste:
6761 cmd = "cmd_paste";
6762 maybeNeedToHandleInRemote = true;
6763 break;
6764 case eContentCommandDelete:
6765 cmd = "cmd_delete";
6766 maybeNeedToHandleInRemote = true;
6767 break;
6768 case eContentCommandUndo:
6769 cmd = "cmd_undo";
6770 maybeNeedToHandleInRemote = true;
6771 break;
6772 case eContentCommandRedo:
6773 cmd = "cmd_redo";
6774 maybeNeedToHandleInRemote = true;
6775 break;
6776 case eContentCommandPasteTransferable:
6777 cmd = "cmd_pasteTransferable";
6778 break;
6779 case eContentCommandLookUpDictionary:
6780 cmd = "cmd_lookUpDictionary";
6781 break;
6782 default:
6783 return NS_ERROR_NOT_IMPLEMENTED;
6784 }
6785 if (XRE_IsParentProcess() && maybeNeedToHandleInRemote) {
6786 if (BrowserParent* remote = BrowserParent::GetFocused()) {
6787 if (!aEvent->mOnlyEnabledCheck) {
6788 remote->SendSimpleContentCommandEvent(*aEvent);
6789 }
6790 // XXX The command may be disabled in the parent process. Perhaps, we
6791 // should set actual enabled state in the parent process here and there
6792 // should be another bool flag which indicates whether the content is sent
6793 // to a remote process.
6794 aEvent->mIsEnabled = true;
6795 aEvent->mSucceeded = true;
6796 return NS_OK;
6797 }
6798 }
6799 // If user tries to do something, user must try to do it in visible window.
6800 // So, let's retrieve controller of visible window.
6801 nsCOMPtr<nsIController> controller;
6802 nsresult rv =
6803 root->GetControllerForCommand(cmd, true, getter_AddRefs(controller));
6804 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6804); return rv; } } while (false)
;
6805 if (!controller) {
6806 // When GetControllerForCommand succeeded but there is no controller, the
6807 // command isn't supported.
6808 aEvent->mIsEnabled = false;
6809 } else {
6810 bool canDoIt;
6811 rv = controller->IsCommandEnabled(cmd, &canDoIt);
6812 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6812); return rv; } } while (false)
;
6813 aEvent->mIsEnabled = canDoIt;
6814 if (canDoIt && !aEvent->mOnlyEnabledCheck) {
6815 switch (aEvent->mMessage) {
6816 case eContentCommandPasteTransferable: {
6817 BrowserParent* remote = BrowserParent::GetFocused();
6818 if (remote) {
6819 IPCTransferable ipcTransferable;
6820 nsContentUtils::TransferableToIPCTransferable(
6821 aEvent->mTransferable, &ipcTransferable, false,
6822 remote->Manager());
6823 remote->SendPasteTransferable(std::move(ipcTransferable));
6824 rv = NS_OK;
6825 } else {
6826 nsCOMPtr<nsICommandController> commandController =
6827 do_QueryInterface(controller);
6828 NS_ENSURE_STATE(commandController)do { if ((__builtin_expect(!!(!(commandController)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "commandController" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6828); return NS_ERROR_UNEXPECTED; } } while (false)
;
6829
6830 RefPtr<nsCommandParams> params = new nsCommandParams();
6831 rv = params->SetISupports("transferable", aEvent->mTransferable);
6832 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6832)
) {
6833 return rv;
6834 }
6835 rv = commandController->DoCommandWithParams(cmd, params);
6836 }
6837 break;
6838 }
6839
6840 case eContentCommandLookUpDictionary: {
6841 nsCOMPtr<nsICommandController> commandController =
6842 do_QueryInterface(controller);
6843 if (NS_WARN_IF(!commandController)NS_warn_if_impl(!commandController, "!commandController", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6843)
) {
6844 return NS_ERROR_FAILURE;
6845 }
6846
6847 RefPtr<nsCommandParams> params = new nsCommandParams();
6848 rv = params->SetInt("x", aEvent->mRefPoint.x);
6849 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6849)
) {
6850 return rv;
6851 }
6852
6853 rv = params->SetInt("y", aEvent->mRefPoint.y);
6854 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6854)
) {
6855 return rv;
6856 }
6857
6858 rv = commandController->DoCommandWithParams(cmd, params);
6859 break;
6860 }
6861
6862 default:
6863 rv = controller->DoCommand(cmd);
6864 break;
6865 }
6866 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6866); return rv; } } while (false)
;
6867 }
6868 }
6869 aEvent->mSucceeded = true;
6870 return NS_OK;
6871}
6872
6873nsresult EventStateManager::DoContentCommandInsertTextEvent(
6874 WidgetContentCommandEvent* aEvent) {
6875 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6875); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 6875; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6876 MOZ_ASSERT(aEvent->mMessage == eContentCommandInsertText)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eContentCommandInsertText)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aEvent->mMessage == eContentCommandInsertText))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eContentCommandInsertText"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6876); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eContentCommandInsertText"
")"); do { *((volatile int*)__null) = 6876; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6877 MOZ_DIAGNOSTIC_ASSERT(aEvent->mString.isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mString.isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mString.isSome())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->mString.isSome()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6877); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aEvent->mString.isSome()"
")"); do { *((volatile int*)__null) = 6877; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6878 MOZ_DIAGNOSTIC_ASSERT(!aEvent->mString.ref().IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEvent->mString.ref().IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aEvent->mString.ref().IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aEvent->mString.ref().IsEmpty()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6878); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!aEvent->mString.ref().IsEmpty()"
")"); do { *((volatile int*)__null) = 6878; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6879
6880 aEvent->mIsEnabled = false;
6881 aEvent->mSucceeded = false;
6882
6883 NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(mPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6883); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
6884
6885 if (XRE_IsParentProcess()) {
6886 // Handle it in focused content process if there is.
6887 if (BrowserParent* remote = BrowserParent::GetFocused()) {
6888 if (!aEvent->mOnlyEnabledCheck) {
6889 remote->SendInsertText(*aEvent);
6890 }
6891 // XXX The remote process may be not editable right now. Therefore, this
6892 // may be different from actual state in the remote process.
6893 aEvent->mIsEnabled = true;
6894 aEvent->mSucceeded = true;
6895 return NS_OK;
6896 }
6897 }
6898
6899 // If there is no active editor in this process, we should treat the command
6900 // is disabled.
6901 RefPtr<EditorBase> activeEditor =
6902 nsContentUtils::GetActiveEditor(mPresContext);
6903 if (!activeEditor) {
6904 aEvent->mSucceeded = true;
6905 return NS_OK;
6906 }
6907
6908 nsresult rv = activeEditor->InsertTextAsAction(aEvent->mString.ref());
6909 aEvent->mIsEnabled = rv != NS_SUCCESS_DOM_NO_OPERATION;
6910 aEvent->mSucceeded = NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)));
6911 return NS_OK;
6912}
6913
6914nsresult EventStateManager::DoContentCommandReplaceTextEvent(
6915 WidgetContentCommandEvent* aEvent) {
6916 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6916); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 6916; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6917 MOZ_ASSERT(aEvent->mMessage == eContentCommandReplaceText)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eContentCommandReplaceText)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aEvent->mMessage == eContentCommandReplaceText)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eContentCommandReplaceText"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6917); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eContentCommandReplaceText"
")"); do { *((volatile int*)__null) = 6917; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6918 MOZ_DIAGNOSTIC_ASSERT(aEvent->mString.isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mString.isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mString.isSome())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->mString.isSome()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6918); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aEvent->mString.isSome()"
")"); do { *((volatile int*)__null) = 6918; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6919 MOZ_DIAGNOSTIC_ASSERT(!aEvent->mString.ref().IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEvent->mString.ref().IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aEvent->mString.ref().IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aEvent->mString.ref().IsEmpty()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6919); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!aEvent->mString.ref().IsEmpty()"
")"); do { *((volatile int*)__null) = 6919; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6920
6921 aEvent->mIsEnabled = false;
6922 aEvent->mSucceeded = false;
6923
6924 NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(mPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6924); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
6925
6926 if (XRE_IsParentProcess()) {
6927 // Handle it in focused content process if there is.
6928 if (BrowserParent* remote = BrowserParent::GetFocused()) {
6929 if (!aEvent->mOnlyEnabledCheck) {
6930 Unused << remote->SendReplaceText(*aEvent);
6931 }
6932 // XXX The remote process may be not editable right now. Therefore, this
6933 // may be different from actual state in the remote process.
6934 aEvent->mIsEnabled = true;
6935 aEvent->mSucceeded = true;
6936 return NS_OK;
6937 }
6938 }
6939
6940 // If there is no active editor in this process, we should treat the command
6941 // is disabled.
6942 RefPtr<EditorBase> activeEditor =
6943 nsContentUtils::GetActiveEditor(mPresContext);
6944 if (NS_WARN_IF(!activeEditor)NS_warn_if_impl(!activeEditor, "!activeEditor", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6944)
) {
6945 aEvent->mSucceeded = true;
6946 return NS_OK;
6947 }
6948
6949 RefPtr<TextComposition> composition =
6950 IMEStateManager::GetTextCompositionFor(mPresContext);
6951 if (NS_WARN_IF(composition)NS_warn_if_impl(composition, "composition", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6951)
) {
6952 // We don't support replace text action during composition.
6953 aEvent->mSucceeded = true;
6954 return NS_OK;
6955 }
6956
6957 ContentEventHandler handler(mPresContext);
6958 RefPtr<nsRange> range = handler.GetRangeFromFlatTextOffset(
6959 aEvent, aEvent->mSelection.mOffset,
6960 aEvent->mSelection.mReplaceSrcString.Length());
6961 if (NS_WARN_IF(!range)NS_warn_if_impl(!range, "!range", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6961)
) {
6962 aEvent->mSucceeded = false;
6963 return NS_OK;
6964 }
6965
6966 // If original replacement text isn't matched with selection text, throws
6967 // error.
6968 nsAutoString targetStr;
6969 nsresult rv = handler.GenerateFlatTextContent(range, targetStr);
6970 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6970)
) {
6971 aEvent->mSucceeded = false;
6972 return NS_OK;
6973 }
6974 if (!aEvent->mSelection.mReplaceSrcString.Equals(targetStr)) {
6975 aEvent->mSucceeded = false;
6976 return NS_OK;
6977 }
6978
6979 rv = activeEditor->ReplaceTextAsAction(
6980 aEvent->mString.ref(), range,
6981 TextEditor::AllowBeforeInputEventCancelable::Yes,
6982 aEvent->mSelection.mPreventSetSelection
6983 ? EditorBase::PreventSetSelection::Yes
6984 : EditorBase::PreventSetSelection::No);
6985 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6985)
) {
6986 aEvent->mSucceeded = false;
6987 return NS_OK;
6988 }
6989
6990 aEvent->mIsEnabled = rv != NS_SUCCESS_DOM_NO_OPERATION;
6991 aEvent->mSucceeded = true;
6992 return NS_OK;
6993}
6994
6995nsresult EventStateManager::DoContentCommandScrollEvent(
6996 WidgetContentCommandEvent* aEvent) {
6997 NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(mPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6997); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
6998 PresShell* presShell = mPresContext->GetPresShell();
6999 NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(presShell)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "presShell" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6999); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
7000 NS_ENSURE_TRUE(aEvent->mScroll.mAmount != 0, NS_ERROR_INVALID_ARG)do { if ((__builtin_expect(!!(!(aEvent->mScroll.mAmount !=
0)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE("
"aEvent->mScroll.mAmount != 0" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7000); return NS_ERROR_INVALID_ARG; } } while (false)
;
7001
7002 ScrollUnit scrollUnit;
7003 switch (aEvent->mScroll.mUnit) {
7004 case WidgetContentCommandEvent::eCmdScrollUnit_Line:
7005 scrollUnit = ScrollUnit::LINES;
7006 break;
7007 case WidgetContentCommandEvent::eCmdScrollUnit_Page:
7008 scrollUnit = ScrollUnit::PAGES;
7009 break;
7010 case WidgetContentCommandEvent::eCmdScrollUnit_Whole:
7011 scrollUnit = ScrollUnit::WHOLE;
7012 break;
7013 default:
7014 return NS_ERROR_INVALID_ARG;
7015 }
7016
7017 aEvent->mSucceeded = true;
7018
7019 ScrollContainerFrame* sf =
7020 presShell->GetScrollContainerFrameToScroll(layers::EitherScrollDirection);
7021 aEvent->mIsEnabled =
7022 sf ? (aEvent->mScroll.mIsHorizontal ? WheelHandlingUtils::CanScrollOn(
7023 sf, aEvent->mScroll.mAmount, 0)
7024 : WheelHandlingUtils::CanScrollOn(
7025 sf, 0, aEvent->mScroll.mAmount))
7026 : false;
7027
7028 if (!aEvent->mIsEnabled || aEvent->mOnlyEnabledCheck) {
7029 return NS_OK;
7030 }
7031
7032 nsIntPoint pt(0, 0);
7033 if (aEvent->mScroll.mIsHorizontal) {
7034 pt.x = aEvent->mScroll.mAmount;
7035 } else {
7036 pt.y = aEvent->mScroll.mAmount;
7037 }
7038
7039 // The caller may want synchronous scrolling.
7040 sf->ScrollBy(pt, scrollUnit, ScrollMode::Instant);
7041 return NS_OK;
7042}
7043
7044void EventStateManager::SetActiveManager(EventStateManager* aNewESM,
7045 nsIContent* aContent) {
7046 if (sActiveESM && aNewESM != sActiveESM) {
7047 sActiveESM->SetContentState(nullptr, ElementState::ACTIVE);
7048 }
7049 sActiveESM = aNewESM;
7050 if (sActiveESM && aContent) {
7051 sActiveESM->SetContentState(aContent, ElementState::ACTIVE);
7052 }
7053}
7054
7055void EventStateManager::ClearGlobalActiveContent(EventStateManager* aClearer) {
7056 if (aClearer) {
7057 aClearer->SetContentState(nullptr, ElementState::ACTIVE);
7058 if (sDragOverContent) {
7059 aClearer->SetContentState(nullptr, ElementState::DRAGOVER);
7060 }
7061 }
7062 if (sActiveESM && aClearer != sActiveESM) {
7063 sActiveESM->SetContentState(nullptr, ElementState::ACTIVE);
7064 }
7065 sActiveESM = nullptr;
7066}
7067
7068/******************************************************************/
7069/* mozilla::EventStateManager::DeltaAccumulator */
7070/******************************************************************/
7071
7072void EventStateManager::DeltaAccumulator::InitLineOrPageDelta(
7073 nsIFrame* aTargetFrame, EventStateManager* aESM, WidgetWheelEvent* aEvent) {
7074 MOZ_ASSERT(aESM)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aESM)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aESM))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aESM", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7074); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aESM" ")");
do { *((volatile int*)__null) = 7074; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7075 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7075); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 7075; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7076
7077 // Reset if the previous wheel event is too old.
7078 if (!mLastTime.IsNull()) {
7079 TimeDuration duration = TimeStamp::Now() - mLastTime;
7080 if (duration.ToMilliseconds() >
7081 StaticPrefs::mousewheel_transaction_timeout()) {
7082 Reset();
7083 }
7084 }
7085 // If we have accumulated delta, we may need to reset it.
7086 if (IsInTransaction()) {
7087 // If wheel event type is changed, reset the values.
7088 if (mHandlingDeltaMode != aEvent->mDeltaMode ||
7089 mIsNoLineOrPageDeltaDevice != aEvent->mIsNoLineOrPageDelta) {
7090 Reset();
7091 } else {
7092 // If the delta direction is changed, we should reset only the
7093 // accumulated values.
7094 if (mX && aEvent->mDeltaX && ((aEvent->mDeltaX > 0.0) != (mX > 0.0))) {
7095 mX = mPendingScrollAmountX = 0.0;
7096 }
7097 if (mY && aEvent->mDeltaY && ((aEvent->mDeltaY > 0.0) != (mY > 0.0))) {
7098 mY = mPendingScrollAmountY = 0.0;
7099 }
7100 }
7101 }
7102
7103 mHandlingDeltaMode = aEvent->mDeltaMode;
7104 mIsNoLineOrPageDeltaDevice = aEvent->mIsNoLineOrPageDelta;
7105
7106 {
7107 ScrollContainerFrame* scrollTarget = aESM->ComputeScrollTarget(
7108 aTargetFrame, aEvent, COMPUTE_DEFAULT_ACTION_TARGET);
7109 nsPresContext* pc = scrollTarget ? scrollTarget->PresContext()
7110 : aTargetFrame->PresContext();
7111 aEvent->mScrollAmount = aESM->GetScrollAmount(pc, aEvent, scrollTarget);
7112 }
7113
7114 // If it's handling neither a device that does not provide line or page deltas
7115 // nor delta values multiplied by prefs, we must not modify lineOrPageDelta
7116 // values.
7117 // TODO(emilio): Does this care about overridden scroll speed?
7118 if (!mIsNoLineOrPageDeltaDevice &&
7119 !EventStateManager::WheelPrefs::GetInstance()
7120 ->NeedToComputeLineOrPageDelta(aEvent)) {
7121 // Set the delta values to mX and mY. They would be used when above block
7122 // resets mX/mY/mPendingScrollAmountX/mPendingScrollAmountY if the direction
7123 // is changed.
7124 // NOTE: We shouldn't accumulate the delta values, it might could cause
7125 // overflow even though it's not a realistic situation.
7126 if (aEvent->mDeltaX) {
7127 mX = aEvent->mDeltaX;
7128 }
7129 if (aEvent->mDeltaY) {
7130 mY = aEvent->mDeltaY;
7131 }
7132 mLastTime = TimeStamp::Now();
7133 return;
7134 }
7135
7136 mX += aEvent->mDeltaX;
7137 mY += aEvent->mDeltaY;
7138
7139 if (mHandlingDeltaMode == WheelEvent_Binding::DOM_DELTA_PIXEL) {
7140 // Records pixel delta values and init mLineOrPageDeltaX and
7141 // mLineOrPageDeltaY for wheel events which are caused by pixel only
7142 // devices. Ignore mouse wheel transaction for computing this. The
7143 // lineOrPageDelta values will be used by dispatching legacy
7144 // eMouseScrollEventClass (DOMMouseScroll) but not be used for scrolling
7145 // of default action. The transaction should be used only for the default
7146 // action.
7147 auto scrollAmountInCSSPixels =
7148 CSSIntSize::FromAppUnitsRounded(aEvent->mScrollAmount);
7149
7150 aEvent->mLineOrPageDeltaX = RoundDown(mX) / scrollAmountInCSSPixels.width;
7151 aEvent->mLineOrPageDeltaY = RoundDown(mY) / scrollAmountInCSSPixels.height;
7152
7153 mX -= aEvent->mLineOrPageDeltaX * scrollAmountInCSSPixels.width;
7154 mY -= aEvent->mLineOrPageDeltaY * scrollAmountInCSSPixels.height;
7155 } else {
7156 aEvent->mLineOrPageDeltaX = RoundDown(mX);
7157 aEvent->mLineOrPageDeltaY = RoundDown(mY);
7158 mX -= aEvent->mLineOrPageDeltaX;
7159 mY -= aEvent->mLineOrPageDeltaY;
7160 }
7161
7162 mLastTime = TimeStamp::Now();
7163}
7164
7165void EventStateManager::DeltaAccumulator::Reset() {
7166 mX = mY = 0.0;
7167 mPendingScrollAmountX = mPendingScrollAmountY = 0.0;
7168 mHandlingDeltaMode = UINT32_MAX(4294967295U);
7169 mIsNoLineOrPageDeltaDevice = false;
7170}
7171
7172nsIntPoint
7173EventStateManager::DeltaAccumulator::ComputeScrollAmountForDefaultAction(
7174 WidgetWheelEvent* aEvent, const nsIntSize& aScrollAmountInDevPixels) {
7175 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7175); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 7175; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7176
7177 DeltaValues acceleratedDelta = WheelTransaction::AccelerateWheelDelta(aEvent);
7178
7179 nsIntPoint result(0, 0);
7180 if (aEvent->mDeltaMode == WheelEvent_Binding::DOM_DELTA_PIXEL) {
7181 mPendingScrollAmountX += acceleratedDelta.deltaX;
7182 mPendingScrollAmountY += acceleratedDelta.deltaY;
7183 } else {
7184 mPendingScrollAmountX +=
7185 aScrollAmountInDevPixels.width * acceleratedDelta.deltaX;
7186 mPendingScrollAmountY +=
7187 aScrollAmountInDevPixels.height * acceleratedDelta.deltaY;
7188 }
7189 result.x = RoundDown(mPendingScrollAmountX);
7190 result.y = RoundDown(mPendingScrollAmountY);
7191 mPendingScrollAmountX -= result.x;
7192 mPendingScrollAmountY -= result.y;
7193
7194 return result;
7195}
7196
7197/******************************************************************/
7198/* mozilla::EventStateManager::WheelPrefs */
7199/******************************************************************/
7200
7201// static
7202EventStateManager::WheelPrefs* EventStateManager::WheelPrefs::GetInstance() {
7203 if (!sInstance) {
7204 sInstance = new WheelPrefs();
7205 }
7206 return sInstance;
7207}
7208
7209// static
7210void EventStateManager::WheelPrefs::Shutdown() {
7211 delete sInstance;
7212 sInstance = nullptr;
7213}
7214
7215// static
7216void EventStateManager::WheelPrefs::OnPrefChanged(const char* aPrefName,
7217 void* aClosure) {
7218 // forget all prefs, it's not problem for performance.
7219 sInstance->Reset();
7220 DeltaAccumulator::GetInstance()->Reset();
7221}
7222
7223EventStateManager::WheelPrefs::WheelPrefs() {
7224 Reset();
7225 Preferences::RegisterPrefixCallback(OnPrefChanged, "mousewheel.");
7226}
7227
7228EventStateManager::WheelPrefs::~WheelPrefs() {
7229 Preferences::UnregisterPrefixCallback(OnPrefChanged, "mousewheel.");
7230}
7231
7232void EventStateManager::WheelPrefs::Reset() { memset(mInit, 0, sizeof(mInit)); }
7233
7234EventStateManager::WheelPrefs::Index EventStateManager::WheelPrefs::GetIndexFor(
7235 const WidgetWheelEvent* aEvent) {
7236 if (!aEvent) {
7237 return INDEX_DEFAULT;
7238 }
7239
7240 Modifiers modifiers = (aEvent->mModifiers & (MODIFIER_ALT | MODIFIER_CONTROL |
7241 MODIFIER_META | MODIFIER_SHIFT));
7242
7243 switch (modifiers) {
7244 case MODIFIER_ALT:
7245 return INDEX_ALT;
7246 case MODIFIER_CONTROL:
7247 return INDEX_CONTROL;
7248 case MODIFIER_META:
7249 return INDEX_META;
7250 case MODIFIER_SHIFT:
7251 return INDEX_SHIFT;
7252 default:
7253 // If two or more modifier keys are pressed, we should use default
7254 // settings.
7255 return INDEX_DEFAULT;
7256 }
7257}
7258
7259void EventStateManager::WheelPrefs::GetBasePrefName(
7260 EventStateManager::WheelPrefs::Index aIndex, nsACString& aBasePrefName) {
7261 aBasePrefName.AssignLiteral("mousewheel.");
7262 switch (aIndex) {
7263 case INDEX_ALT:
7264 aBasePrefName.AppendLiteral("with_alt.");
7265 break;
7266 case INDEX_CONTROL:
7267 aBasePrefName.AppendLiteral("with_control.");
7268 break;
7269 case INDEX_META:
7270 aBasePrefName.AppendLiteral("with_meta.");
7271 break;
7272 case INDEX_SHIFT:
7273 aBasePrefName.AppendLiteral("with_shift.");
7274 break;
7275 case INDEX_DEFAULT:
7276 default:
7277 aBasePrefName.AppendLiteral("default.");
7278 break;
7279 }
7280}
7281
7282void EventStateManager::WheelPrefs::Init(
7283 EventStateManager::WheelPrefs::Index aIndex) {
7284 if (mInit[aIndex]) {
7285 return;
7286 }
7287 mInit[aIndex] = true;
7288
7289 nsAutoCString basePrefName;
7290 GetBasePrefName(aIndex, basePrefName);
7291
7292 nsAutoCString prefNameX(basePrefName);
7293 prefNameX.AppendLiteral("delta_multiplier_x");
7294 mMultiplierX[aIndex] =
7295 static_cast<double>(Preferences::GetInt(prefNameX.get(), 100)) / 100;
7296
7297 nsAutoCString prefNameY(basePrefName);
7298 prefNameY.AppendLiteral("delta_multiplier_y");
7299 mMultiplierY[aIndex] =
7300 static_cast<double>(Preferences::GetInt(prefNameY.get(), 100)) / 100;
7301
7302 nsAutoCString prefNameZ(basePrefName);
7303 prefNameZ.AppendLiteral("delta_multiplier_z");
7304 mMultiplierZ[aIndex] =
7305 static_cast<double>(Preferences::GetInt(prefNameZ.get(), 100)) / 100;
7306
7307 nsAutoCString prefNameAction(basePrefName);
7308 prefNameAction.AppendLiteral("action");
7309 int32_t action = Preferences::GetInt(prefNameAction.get(), ACTION_SCROLL);
7310 if (action < int32_t(ACTION_NONE) || action > int32_t(ACTION_LAST)) {
7311 NS_WARNING("Unsupported action pref value, replaced with 'Scroll'.")NS_DebugBreak(NS_DEBUG_WARNING, "Unsupported action pref value, replaced with 'Scroll'."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7311)
;
7312 action = ACTION_SCROLL;
7313 }
7314 mActions[aIndex] = static_cast<Action>(action);
7315
7316 // Compute action values overridden by .override_x pref.
7317 // At present, override is possible only for the x-direction
7318 // because this pref is introduced mainly for tilt wheels.
7319 // Note that ACTION_HORIZONTALIZED_SCROLL isn't a valid value for this pref
7320 // because it affects only to deltaY.
7321 prefNameAction.AppendLiteral(".override_x");
7322 int32_t actionOverrideX = Preferences::GetInt(prefNameAction.get(), -1);
7323 if (actionOverrideX < -1 || actionOverrideX > int32_t(ACTION_LAST) ||
7324 actionOverrideX == ACTION_HORIZONTALIZED_SCROLL) {
7325 NS_WARNING("Unsupported action override pref value, didn't override.")NS_DebugBreak(NS_DEBUG_WARNING, "Unsupported action override pref value, didn't override."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7325)
;
7326 actionOverrideX = -1;
7327 }
7328 mOverriddenActionsX[aIndex] = (actionOverrideX == -1)
7329 ? static_cast<Action>(action)
7330 : static_cast<Action>(actionOverrideX);
7331}
7332
7333void EventStateManager::WheelPrefs::GetMultiplierForDeltaXAndY(
7334 const WidgetWheelEvent* aEvent, Index aIndex, double* aMultiplierForDeltaX,
7335 double* aMultiplierForDeltaY) {
7336 *aMultiplierForDeltaX = mMultiplierX[aIndex];
7337 *aMultiplierForDeltaY = mMultiplierY[aIndex];
7338 // If the event has been horizontalized(I.e. treated as a horizontal wheel
7339 // scroll for a vertical wheel scroll), then we should swap mMultiplierX and
7340 // mMultiplierY. By doing this, multipliers will still apply to the delta
7341 // values they origianlly corresponded to.
7342 if (aEvent->mDeltaValuesHorizontalizedForDefaultHandler &&
7343 ComputeActionFor(aEvent) == ACTION_HORIZONTALIZED_SCROLL) {
7344 std::swap(*aMultiplierForDeltaX, *aMultiplierForDeltaY);
7345 }
7346}
7347
7348void EventStateManager::WheelPrefs::ApplyUserPrefsToDelta(
7349 WidgetWheelEvent* aEvent) {
7350 if (aEvent->mCustomizedByUserPrefs) {
7351 return;
7352 }
7353
7354 Index index = GetIndexFor(aEvent);
7355 Init(index);
7356
7357 double multiplierForDeltaX = 1.0, multiplierForDeltaY = 1.0;
7358 GetMultiplierForDeltaXAndY(aEvent, index, &multiplierForDeltaX,
7359 &multiplierForDeltaY);
7360 aEvent->mDeltaX *= multiplierForDeltaX;
7361 aEvent->mDeltaY *= multiplierForDeltaY;
7362 aEvent->mDeltaZ *= mMultiplierZ[index];
7363
7364 // If the multiplier is 1.0 or -1.0, i.e., it doesn't change the absolute
7365 // value, we should use lineOrPageDelta values which were set by widget.
7366 // Otherwise, we need to compute them from accumulated delta values.
7367 if (!NeedToComputeLineOrPageDelta(aEvent)) {
7368 aEvent->mLineOrPageDeltaX *= static_cast<int32_t>(multiplierForDeltaX);
7369 aEvent->mLineOrPageDeltaY *= static_cast<int32_t>(multiplierForDeltaY);
7370 } else {
7371 aEvent->mLineOrPageDeltaX = 0;
7372 aEvent->mLineOrPageDeltaY = 0;
7373 }
7374
7375 aEvent->mCustomizedByUserPrefs =
7376 ((mMultiplierX[index] != 1.0) || (mMultiplierY[index] != 1.0) ||
7377 (mMultiplierZ[index] != 1.0));
7378}
7379
7380void EventStateManager::WheelPrefs::CancelApplyingUserPrefsFromOverflowDelta(
7381 WidgetWheelEvent* aEvent) {
7382 Index index = GetIndexFor(aEvent);
7383 Init(index);
7384
7385 // XXX If the multiplier pref value is negative, the scroll direction was
7386 // changed and caused to scroll different direction. In such case,
7387 // this method reverts the sign of overflowDelta. Does it make widget
7388 // happy? Although, widget can know the pref applied delta values by
7389 // referrencing the deltaX and deltaY of the event.
7390
7391 double multiplierForDeltaX = 1.0, multiplierForDeltaY = 1.0;
7392 GetMultiplierForDeltaXAndY(aEvent, index, &multiplierForDeltaX,
7393 &multiplierForDeltaY);
7394 if (multiplierForDeltaX) {
7395 aEvent->mOverflowDeltaX /= multiplierForDeltaX;
7396 }
7397 if (multiplierForDeltaY) {
7398 aEvent->mOverflowDeltaY /= multiplierForDeltaY;
7399 }
7400}
7401
7402EventStateManager::WheelPrefs::Action
7403EventStateManager::WheelPrefs::ComputeActionFor(
7404 const WidgetWheelEvent* aEvent) {
7405 Index index = GetIndexFor(aEvent);
7406 Init(index);
7407
7408 bool deltaXPreferred = (Abs(aEvent->mDeltaX) > Abs(aEvent->mDeltaY) &&
7409 Abs(aEvent->mDeltaX) > Abs(aEvent->mDeltaZ));
7410 Action* actions = deltaXPreferred ? mOverriddenActionsX : mActions;
7411 if (actions[index] == ACTION_NONE || actions[index] == ACTION_SCROLL ||
7412 actions[index] == ACTION_HORIZONTALIZED_SCROLL) {
7413 return actions[index];
7414 }
7415
7416 // Momentum events shouldn't run special actions.
7417 if (aEvent->mIsMomentum) {
7418 // Use the default action. Note that user might kill the wheel scrolling.
7419 Init(INDEX_DEFAULT);
7420 if (actions[INDEX_DEFAULT] == ACTION_SCROLL ||
7421 actions[INDEX_DEFAULT] == ACTION_HORIZONTALIZED_SCROLL) {
7422 return actions[INDEX_DEFAULT];
7423 }
7424 return ACTION_NONE;
7425 }
7426
7427 return actions[index];
7428}
7429
7430bool EventStateManager::WheelPrefs::NeedToComputeLineOrPageDelta(
7431 const WidgetWheelEvent* aEvent) {
7432 Index index = GetIndexFor(aEvent);
7433 Init(index);
7434
7435 return (mMultiplierX[index] != 1.0 && mMultiplierX[index] != -1.0) ||
7436 (mMultiplierY[index] != 1.0 && mMultiplierY[index] != -1.0);
7437}
7438
7439void EventStateManager::WheelPrefs::GetUserPrefsForEvent(
7440 const WidgetWheelEvent* aEvent, double* aOutMultiplierX,
7441 double* aOutMultiplierY) {
7442 Index index = GetIndexFor(aEvent);
7443 Init(index);
7444
7445 double multiplierForDeltaX = 1.0, multiplierForDeltaY = 1.0;
7446 GetMultiplierForDeltaXAndY(aEvent, index, &multiplierForDeltaX,
7447 &multiplierForDeltaY);
7448 *aOutMultiplierX = multiplierForDeltaX;
7449 *aOutMultiplierY = multiplierForDeltaY;
7450}
7451
7452// static
7453Maybe<layers::APZWheelAction> EventStateManager::APZWheelActionFor(
7454 const WidgetWheelEvent* aEvent) {
7455 if (aEvent->mMessage != eWheel) {
7456 return Nothing();
7457 }
7458 WheelPrefs::Action action =
7459 WheelPrefs::GetInstance()->ComputeActionFor(aEvent);
7460 switch (action) {
7461 case WheelPrefs::ACTION_SCROLL:
7462 case WheelPrefs::ACTION_HORIZONTALIZED_SCROLL:
7463 return Some(layers::APZWheelAction::Scroll);
7464 case WheelPrefs::ACTION_PINCH_ZOOM:
7465 return Some(layers::APZWheelAction::PinchZoom);
7466 default:
7467 return Nothing();
7468 }
7469}
7470
7471// static
7472WheelDeltaAdjustmentStrategy EventStateManager::GetWheelDeltaAdjustmentStrategy(
7473 const WidgetWheelEvent& aEvent) {
7474 if (aEvent.mMessage != eWheel) {
7475 return WheelDeltaAdjustmentStrategy::eNone;
7476 }
7477 switch (WheelPrefs::GetInstance()->ComputeActionFor(&aEvent)) {
7478 case WheelPrefs::ACTION_SCROLL:
7479 if (StaticPrefs::mousewheel_autodir_enabled() && 0 == aEvent.mDeltaZ) {
7480 if (StaticPrefs::mousewheel_autodir_honourroot()) {
7481 return WheelDeltaAdjustmentStrategy::eAutoDirWithRootHonour;
7482 }
7483 return WheelDeltaAdjustmentStrategy::eAutoDir;
7484 }
7485 return WheelDeltaAdjustmentStrategy::eNone;
7486 case WheelPrefs::ACTION_HORIZONTALIZED_SCROLL:
7487 return WheelDeltaAdjustmentStrategy::eHorizontalize;
7488 default:
7489 break;
7490 }
7491 return WheelDeltaAdjustmentStrategy::eNone;
7492}
7493
7494void EventStateManager::GetUserPrefsForWheelEvent(
7495 const WidgetWheelEvent* aEvent, double* aOutMultiplierX,
7496 double* aOutMultiplierY) {
7497 WheelPrefs::GetInstance()->GetUserPrefsForEvent(aEvent, aOutMultiplierX,
7498 aOutMultiplierY);
7499}
7500
7501bool EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedX(
7502 const WidgetWheelEvent* aEvent) {
7503 Index index = GetIndexFor(aEvent);
7504 Init(index);
7505 return Abs(mMultiplierX[index]) >=
7506 MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
7507}
7508
7509bool EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedY(
7510 const WidgetWheelEvent* aEvent) {
7511 Index index = GetIndexFor(aEvent);
7512 Init(index);
7513 return Abs(mMultiplierY[index]) >=
7514 MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
7515}
7516
7517} // namespace mozilla

/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h

1/* -*- Mode: C++; tab-width: 2; 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/* A class for optional values and in-place lazy construction. */
8
9#ifndef mozilla_Maybe_h
10#define mozilla_Maybe_h
11
12#include <functional>
13#include <new> // for placement new
14#include <ostream>
15#include <type_traits>
16#include <utility>
17
18#include "mozilla/Alignment.h"
19#include "mozilla/Assertions.h"
20#include "mozilla/Attributes.h"
21#include "mozilla/MaybeStorageBase.h"
22#include "mozilla/MemoryChecking.h"
23#include "mozilla/OperatorNewExtensions.h"
24#include "mozilla/Poison.h"
25#include "mozilla/ThreadSafety.h"
26
27class nsCycleCollectionTraversalCallback;
28
29template <typename T>
30inline void CycleCollectionNoteChild(
31 nsCycleCollectionTraversalCallback& aCallback, T* aChild, const char* aName,
32 uint32_t aFlags);
33
34namespace mozilla {
35
36struct Nothing {};
37
38inline constexpr bool operator==(const Nothing&, const Nothing&) {
39 return true;
40}
41
42template <class T>
43class Maybe;
44
45namespace detail {
46
47// You would think that poisoning Maybe instances could just be a call
48// to mozWritePoison. Unfortunately, using a simple call to
49// mozWritePoison generates poor code on MSVC for small structures. The
50// generated code contains (always not-taken) branches and does a bunch
51// of setup for `rep stos{l,q}`, even though we know at compile time
52// exactly how many words we're poisoning. Instead, we're going to
53// force MSVC to generate the code we want via recursive templates.
54
55// Write the given poisonValue into p at offset*sizeof(uintptr_t).
56template <size_t offset>
57inline void WritePoisonAtOffset(void* p, const uintptr_t poisonValue) {
58 memcpy(static_cast<char*>(p) + offset * sizeof(poisonValue), &poisonValue,
59 sizeof(poisonValue));
60}
61
62template <size_t Offset, size_t NOffsets>
63struct InlinePoisoner {
64 static void poison(void* p, const uintptr_t poisonValue) {
65 WritePoisonAtOffset<Offset>(p, poisonValue);
66 InlinePoisoner<Offset + 1, NOffsets>::poison(p, poisonValue);
67 }
68};
69
70template <size_t N>
71struct InlinePoisoner<N, N> {
72 static void poison(void*, const uintptr_t) {
73 // All done!
74 }
75};
76
77// We can't generate inline code for large structures, though, because we'll
78// blow out recursive template instantiation limits, and the code would be
79// bloated to boot. So provide a fallback to the out-of-line poisoner.
80template <size_t ObjectSize>
81struct OutOfLinePoisoner {
82 static MOZ_NEVER_INLINE__attribute__((noinline)) void poison(void* p, const uintptr_t) {
83 mozWritePoison(p, ObjectSize);
84 }
85};
86
87template <typename T>
88inline void PoisonObject(T* p) {
89 const uintptr_t POISON = mozPoisonValue();
90 std::conditional_t<(sizeof(T) <= 8 * sizeof(POISON)),
91 InlinePoisoner<0, sizeof(T) / sizeof(POISON)>,
92 OutOfLinePoisoner<sizeof(T)>>::poison(p, POISON);
93}
94
95template <typename T>
96struct MaybePoisoner {
97 static const size_t N = sizeof(T);
98
99 static void poison(void* aPtr) {
100#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED1
101 if (N >= sizeof(uintptr_t)) {
102 PoisonObject(static_cast<std::remove_cv_t<T>*>(aPtr));
103 }
104#endif
105 MOZ_MAKE_MEM_UNDEFINED(aPtr, N)do { } while (0);
106 }
107};
108
109template <typename T,
110 bool TriviallyDestructibleAndCopyable =
111 IsTriviallyDestructibleAndCopyable<T>,
112 bool Copyable = std::is_copy_constructible_v<T>,
113 bool Movable = std::is_move_constructible_v<T>>
114class Maybe_CopyMove_Enabler;
115
116#define MOZ_MAYBE_COPY_OPS() \
117 Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler& aOther) { \
118 if (downcast(aOther).isSome()) { \
119 downcast(*this).emplace(*downcast(aOther)); \
120 } \
121 } \
122 \
123 Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler& aOther) { \
124 return downcast(*this).template operator= <T>(downcast(aOther)); \
125 }
126
127#define MOZ_MAYBE_MOVE_OPS() \
128 constexpr Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&& aOther) { \
129 if (downcast(aOther).isSome()) { \
130 downcast(*this).emplace(std::move(*downcast(aOther))); \
131 downcast(aOther).reset(); \
132 } \
133 } \
134 \
135 constexpr Maybe_CopyMove_Enabler& operator=( \
136 Maybe_CopyMove_Enabler&& aOther) { \
137 downcast(*this).template operator= <T>(std::move(downcast(aOther))); \
138 \
139 return *this; \
140 }
141
142#define MOZ_MAYBE_DOWNCAST() \
143 static constexpr Maybe<T>& downcast(Maybe_CopyMove_Enabler& aObj) { \
144 return static_cast<Maybe<T>&>(aObj); \
145 } \
146 static constexpr const Maybe<T>& downcast( \
147 const Maybe_CopyMove_Enabler& aObj) { \
148 return static_cast<const Maybe<T>&>(aObj); \
149 }
150
151template <typename T>
152class Maybe_CopyMove_Enabler<T, true, true, true> {
153 public:
154 Maybe_CopyMove_Enabler() = default;
155
156 Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = default;
157 Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = default;
158 constexpr Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&& aOther) {
159 downcast(aOther).reset();
160 }
161 constexpr Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&& aOther) {
162 downcast(aOther).reset();
163 return *this;
164 }
165
166 private:
167 MOZ_MAYBE_DOWNCAST()
168};
169
170template <typename T>
171class Maybe_CopyMove_Enabler<T, true, false, true> {
172 public:
173 Maybe_CopyMove_Enabler() = default;
174
175 Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = delete;
176 Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = delete;
177 constexpr Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&& aOther) {
178 downcast(aOther).reset();
179 }
180 constexpr Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&& aOther) {
181 downcast(aOther).reset();
182 return *this;
183 }
184
185 private:
186 MOZ_MAYBE_DOWNCAST()
187};
188
189template <typename T>
190class Maybe_CopyMove_Enabler<T, false, true, true> {
191 public:
192 Maybe_CopyMove_Enabler() = default;
193
194 MOZ_MAYBE_COPY_OPS()
195 MOZ_MAYBE_MOVE_OPS()
196
197 private:
198 MOZ_MAYBE_DOWNCAST()
199};
200
201template <typename T>
202class Maybe_CopyMove_Enabler<T, false, false, true> {
203 public:
204 Maybe_CopyMove_Enabler() = default;
205
206 Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = delete;
207 Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = delete;
208 MOZ_MAYBE_MOVE_OPS()
209
210 private:
211 MOZ_MAYBE_DOWNCAST()
212};
213
214template <typename T>
215class Maybe_CopyMove_Enabler<T, false, true, false> {
216 public:
217 Maybe_CopyMove_Enabler() = default;
218
219 MOZ_MAYBE_COPY_OPS()
220 Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&&) = delete;
221 Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&&) = delete;
222
223 private:
224 MOZ_MAYBE_DOWNCAST()
225};
226
227template <typename T, bool TriviallyDestructibleAndCopyable>
228class Maybe_CopyMove_Enabler<T, TriviallyDestructibleAndCopyable, false,
229 false> {
230 public:
231 Maybe_CopyMove_Enabler() = default;
232
233 Maybe_CopyMove_Enabler(const Maybe_CopyMove_Enabler&) = delete;
234 Maybe_CopyMove_Enabler& operator=(const Maybe_CopyMove_Enabler&) = delete;
235 Maybe_CopyMove_Enabler(Maybe_CopyMove_Enabler&&) = delete;
236 Maybe_CopyMove_Enabler& operator=(Maybe_CopyMove_Enabler&&) = delete;
237};
238
239#undef MOZ_MAYBE_COPY_OPS
240#undef MOZ_MAYBE_MOVE_OPS
241#undef MOZ_MAYBE_DOWNCAST
242
243template <typename T, bool TriviallyDestructibleAndCopyable =
244 IsTriviallyDestructibleAndCopyable<T>>
245struct MaybeStorage;
246
247template <typename T>
248struct MaybeStorage<T, false> : MaybeStorageBase<T> {
249 protected:
250 char mIsSome = false; // not bool -- guarantees minimal space consumption
251
252 MaybeStorage() = default;
24
Calling defaulted default constructor for 'MaybeStorageBase<mozilla::WidgetMouseEvent, false>'
29
Returning from default constructor for 'MaybeStorageBase<mozilla::WidgetMouseEvent, false>'
30
Returning without writing to 'this->mStorage.val.mClickTarget.mRawPtr'
253 explicit MaybeStorage(const T& aVal)
254 : MaybeStorageBase<T>{aVal}, mIsSome{true} {}
255 explicit MaybeStorage(T&& aVal)
256 : MaybeStorageBase<T>{std::move(aVal)}, mIsSome{true} {}
257
258 template <typename... Args>
259 explicit MaybeStorage(std::in_place_t, Args&&... aArgs)
260 : MaybeStorageBase<T>{std::in_place, std::forward<Args>(aArgs)...},
261 mIsSome{true} {}
262
263 public:
264 // Copy and move operations are no-ops, since copying is moving is implemented
265 // by Maybe_CopyMove_Enabler.
266
267 MaybeStorage(const MaybeStorage&) : MaybeStorageBase<T>{} {}
268 MaybeStorage& operator=(const MaybeStorage&) { return *this; }
269 MaybeStorage(MaybeStorage&&) : MaybeStorageBase<T>{} {}
270 MaybeStorage& operator=(MaybeStorage&&) { return *this; }
271
272 ~MaybeStorage() {
273 if (mIsSome
42.1
Field 'mIsSome' is 0
42.1
Field 'mIsSome' is 0
42.1
Field 'mIsSome' is 0
42.1
Field 'mIsSome' is 0
42.1
Field 'mIsSome' is 0
42.1
Field 'mIsSome' is 0
) {
43
Taking false branch
274 this->addr()->T::~T();
275 }
276 }
44
Calling implicit destructor for 'MaybeStorageBase<mozilla::WidgetMouseEvent, false>'
45
Calling '~Union'
277};
278
279template <typename T>
280struct MaybeStorage<T, true> : MaybeStorageBase<T> {
281 protected:
282 char mIsSome = false; // not bool -- guarantees minimal space consumption
283
284 constexpr MaybeStorage() = default;
285 constexpr explicit MaybeStorage(const T& aVal)
286 : MaybeStorageBase<T>{aVal}, mIsSome{true} {}
287 constexpr explicit MaybeStorage(T&& aVal)
288 : MaybeStorageBase<T>{std::move(aVal)}, mIsSome{true} {}
289
290 template <typename... Args>
291 constexpr explicit MaybeStorage(std::in_place_t, Args&&... aArgs)
292 : MaybeStorageBase<T>{std::in_place, std::forward<Args>(aArgs)...},
293 mIsSome{true} {}
294};
295
296template <typename T>
297struct IsMaybeImpl : std::false_type {};
298
299template <typename T>
300struct IsMaybeImpl<Maybe<T>> : std::true_type {};
301
302template <typename T>
303using IsMaybe = IsMaybeImpl<std::decay_t<T>>;
304
305} // namespace detail
306
307template <typename T, typename U = typename std::remove_cv<
308 typename std::remove_reference<T>::type>::type>
309constexpr Maybe<U> Some(T&& aValue);
310
311/*
312 * Maybe is a container class which contains either zero or one elements. It
313 * serves two roles. It can represent values which are *semantically* optional,
314 * augmenting a type with an explicit 'Nothing' value. In this role, it provides
315 * methods that make it easy to work with values that may be missing, along with
316 * equality and comparison operators so that Maybe values can be stored in
317 * containers. Maybe values can be constructed conveniently in expressions using
318 * type inference, as follows:
319 *
320 * void doSomething(Maybe<Foo> aFoo) {
321 * if (aFoo) // Make sure that aFoo contains a value...
322 * aFoo->takeAction(); // and then use |aFoo->| to access it.
323 * } // |*aFoo| also works!
324 *
325 * doSomething(Nothing()); // Passes a Maybe<Foo> containing no value.
326 * doSomething(Some(Foo(100))); // Passes a Maybe<Foo> containing |Foo(100)|.
327 *
328 * You'll note that it's important to check whether a Maybe contains a value
329 * before using it, using conversion to bool, |isSome()|, or |isNothing()|. You
330 * can avoid these checks, and sometimes write more readable code, using
331 * |valueOr()|, |ptrOr()|, and |refOr()|, which allow you to retrieve the value
332 * in the Maybe and provide a default for the 'Nothing' case. You can also use
333 * |apply()| to call a function only if the Maybe holds a value, and |map()| to
334 * transform the value in the Maybe, returning another Maybe with a possibly
335 * different type.
336 *
337 * Maybe's other role is to support lazily constructing objects without using
338 * dynamic storage. A Maybe directly contains storage for a value, but it's
339 * empty by default. |emplace()|, as mentioned above, can be used to construct a
340 * value in Maybe's storage. The value a Maybe contains can be destroyed by
341 * calling |reset()|; this will happen automatically if a Maybe is destroyed
342 * while holding a value.
343 *
344 * It's a common idiom in C++ to use a pointer as a 'Maybe' type, with a null
345 * value meaning 'Nothing' and any other value meaning 'Some'. You can convert
346 * from such a pointer to a Maybe value using 'ToMaybe()'.
347 *
348 * Maybe is inspired by similar types in the standard library of many other
349 * languages (e.g. Haskell's Maybe and Rust's Option). In the C++ world it's
350 * very similar to std::optional, which was proposed for C++14 and originated in
351 * Boost. The most important differences between Maybe and std::optional are:
352 *
353 * - std::optional<T> may be compared with T. We deliberately forbid that.
354 * - std::optional has |valueOr()|, equivalent to Maybe's |valueOr()|, but
355 * lacks corresponding methods for |refOr()| and |ptrOr()|.
356 * - std::optional lacks |map()| and |apply()|, making it less suitable for
357 * functional-style code.
358 * - std::optional lacks many convenience functions that Maybe has. Most
359 * unfortunately, it lacks equivalents of the type-inferred constructor
360 * functions |Some()| and |Nothing()|.
361 */
362template <class T>
363class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Maybe
364 : private detail::MaybeStorage<T>,
365 public detail::Maybe_CopyMove_Enabler<T> {
366 template <typename, bool, bool, bool>
367 friend class detail::Maybe_CopyMove_Enabler;
368
369 template <typename U, typename V>
370 friend constexpr Maybe<V> Some(U&& aValue);
371
372 struct SomeGuard {};
373
374 template <typename U>
375 constexpr Maybe(U&& aValue, SomeGuard)
376 : detail::MaybeStorage<T>{std::forward<U>(aValue)} {}
377
378 using detail::MaybeStorage<T>::mIsSome;
379 using detail::MaybeStorage<T>::mStorage;
380
381 void poisonData() { detail::MaybePoisoner<T>::poison(&mStorage.val); }
382
383 public:
384 using ValueType = T;
385
386 MOZ_ALLOW_TEMPORARY constexpr Maybe() = default;
23
Calling defaulted default constructor for 'MaybeStorage<mozilla::WidgetMouseEvent, false>'
31
Returning from default constructor for 'MaybeStorage<mozilla::WidgetMouseEvent, false>'
32
Returning without writing to 'this->mStorage.val.mClickTarget.mRawPtr'
387
388 MOZ_ALLOW_TEMPORARY MOZ_IMPLICIT constexpr Maybe(Nothing) : Maybe{} {}
389
390 template <typename... Args>
391 constexpr explicit Maybe(std::in_place_t, Args&&... aArgs)
392 : detail::MaybeStorage<T>{std::in_place, std::forward<Args>(aArgs)...} {}
393
394 /**
395 * Maybe<T> can be copy-constructed from a Maybe<U> if T is constructible from
396 * a const U&.
397 */
398 template <typename U,
399 std::enable_if_t<std::is_constructible_v<T, const U&>, bool> = true>
400 MOZ_IMPLICIT Maybe(const Maybe<U>& aOther) {
401 if (aOther.isSome()) {
402 emplace(*aOther);
403 }
404 }
405
406 template <typename U, std::enable_if_t<!std::is_constructible_v<T, const U&>,
407 bool> = true>
408 explicit Maybe(const Maybe<U>& aOther) = delete;
409
410 /**
411 * Maybe<T> can be move-constructed from a Maybe<U> if T is constructible from
412 * a U&&.
413 */
414 template <typename U,
415 std::enable_if_t<std::is_constructible_v<T, U&&>, bool> = true>
416 MOZ_IMPLICIT Maybe(Maybe<U>&& aOther) {
417 if (aOther.isSome()) {
418 emplace(std::move(*aOther));
419 aOther.reset();
420 }
421 }
422 template <typename U,
423 std::enable_if_t<!std::is_constructible_v<T, U&&>, bool> = true>
424 explicit Maybe(Maybe<U>&& aOther) = delete;
425
426 template <typename U,
427 std::enable_if_t<std::is_constructible_v<T, const U&>, bool> = true>
428 Maybe& operator=(const Maybe<U>& aOther) {
429 if (aOther.isSome()) {
430 if (mIsSome) {
431 ref() = aOther.ref();
432 } else {
433 emplace(*aOther);
434 }
435 } else {
436 reset();
437 }
438 return *this;
439 }
440
441 template <typename U, std::enable_if_t<!std::is_constructible_v<T, const U&>,
442 bool> = true>
443 Maybe& operator=(const Maybe<U>& aOther) = delete;
444
445 template <typename U,
446 std::enable_if_t<std::is_constructible_v<T, U&&>, bool> = true>
447 Maybe& operator=(Maybe<U>&& aOther) {
448 if (aOther.isSome()) {
449 if (mIsSome) {
450 ref() = std::move(aOther.ref());
451 } else {
452 emplace(std::move(*aOther));
453 }
454 aOther.reset();
455 } else {
456 reset();
457 }
458
459 return *this;
460 }
461
462 template <typename U,
463 std::enable_if_t<!std::is_constructible_v<T, U&&>, bool> = true>
464 Maybe& operator=(Maybe<U>&& aOther) = delete;
465
466 constexpr Maybe& operator=(Nothing) {
467 reset();
468 return *this;
469 }
470
471 /* Methods that check whether this Maybe contains a value */
472 constexpr explicit operator bool() const { return isSome(); }
473 constexpr bool isSome() const { return mIsSome; }
474 constexpr bool isNothing() const { return !mIsSome; }
475
476 /* Returns the contents of this Maybe<T> by value. Unsafe unless |isSome()|.
477 */
478 constexpr T value() const&;
479 constexpr T value() &&;
480 constexpr T value() const&&;
481
482 /**
483 * Move the contents of this Maybe<T> out of internal storage and return it
484 * without calling the destructor. The internal storage is also reset to
485 * avoid multiple calls. Unsafe unless |isSome()|.
486 */
487 constexpr T extract() {
488 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 488); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 488; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
489 T v = std::move(mStorage.val);
490 reset();
491 return v;
492 }
493
494 /**
495 * Returns the value (possibly |Nothing()|) by moving it out of this Maybe<T>
496 * and leaving |Nothing()| in its place.
497 */
498 Maybe<T> take() { return std::exchange(*this, Nothing()); }
499
500 /*
501 * Returns the contents of this Maybe<T> by value. If |isNothing()|, returns
502 * the default value provided.
503 *
504 * Note: If the value passed to aDefault is not the result of a trivial
505 * expression, but expensive to evaluate, e.g. |valueOr(ExpensiveFunction())|,
506 * use |valueOrFrom| instead, e.g.
507 * |valueOrFrom([arg] { return ExpensiveFunction(arg); })|. This ensures
508 * that the expensive expression is only evaluated when its result will
509 * actually be used.
510 */
511 template <typename V>
512 constexpr T valueOr(V&& aDefault) const {
513 if (isSome()) {
514 return ref();
515 }
516 return std::forward<V>(aDefault);
517 }
518
519 /*
520 * Returns the contents of this Maybe<T> by value. If |isNothing()|, returns
521 * the value returned from the function or functor provided.
522 */
523 template <typename F>
524 constexpr T valueOrFrom(F&& aFunc) const {
525 if (isSome()) {
526 return ref();
527 }
528 return aFunc();
529 }
530
531 /* Returns the contents of this Maybe<T> by pointer. Unsafe unless |isSome()|.
532 */
533 T* ptr();
534 constexpr const T* ptr() const;
535
536 /*
537 * Returns the contents of this Maybe<T> by pointer. If |isNothing()|,
538 * returns the default value provided.
539 */
540 T* ptrOr(T* aDefault) {
541 if (isSome()) {
542 return ptr();
543 }
544 return aDefault;
545 }
546
547 constexpr const T* ptrOr(const T* aDefault) const {
548 if (isSome()) {
549 return ptr();
550 }
551 return aDefault;
552 }
553
554 /*
555 * Returns the contents of this Maybe<T> by pointer. If |isNothing()|,
556 * returns the value returned from the function or functor provided.
557 */
558 template <typename F>
559 T* ptrOrFrom(F&& aFunc) {
560 if (isSome()) {
561 return ptr();
562 }
563 return aFunc();
564 }
565
566 template <typename F>
567 const T* ptrOrFrom(F&& aFunc) const {
568 if (isSome()) {
569 return ptr();
570 }
571 return aFunc();
572 }
573
574 constexpr T* operator->();
575 constexpr const T* operator->() const;
576
577 /* Returns the contents of this Maybe<T> by ref. Unsafe unless |isSome()|. */
578 constexpr T& ref() &;
579 constexpr const T& ref() const&;
580 constexpr T&& ref() &&;
581 constexpr const T&& ref() const&&;
582
583 /*
584 * Returns the contents of this Maybe<T> by ref. If |isNothing()|, returns
585 * the default value provided.
586 */
587 constexpr T& refOr(T& aDefault) {
588 if (isSome()) {
589 return ref();
590 }
591 return aDefault;
592 }
593
594 constexpr const T& refOr(const T& aDefault) const {
595 if (isSome()) {
596 return ref();
597 }
598 return aDefault;
599 }
600
601 /*
602 * Returns the contents of this Maybe<T> by ref. If |isNothing()|, returns the
603 * value returned from the function or functor provided.
604 */
605 template <typename F>
606 constexpr T& refOrFrom(F&& aFunc) {
607 if (isSome()) {
608 return ref();
609 }
610 return aFunc();
611 }
612
613 template <typename F>
614 constexpr const T& refOrFrom(F&& aFunc) const {
615 if (isSome()) {
616 return ref();
617 }
618 return aFunc();
619 }
620
621 constexpr T& operator*() &;
622 constexpr const T& operator*() const&;
623 constexpr T&& operator*() &&;
624 constexpr const T&& operator*() const&&;
625
626 /* If |isSome()|, runs the provided function or functor on the contents of
627 * this Maybe. */
628 template <typename Func>
629 constexpr Maybe& apply(Func&& aFunc) & {
630 if (isSome()) {
631 std::forward<Func>(aFunc)(ref());
632 }
633 return *this;
634 }
635
636 template <typename Func>
637 constexpr const Maybe& apply(Func&& aFunc) const& {
638 if (isSome()) {
639 std::forward<Func>(aFunc)(ref());
640 }
641 return *this;
642 }
643
644 template <typename Func>
645 constexpr Maybe& apply(Func&& aFunc) && {
646 if (isSome()) {
647 std::forward<Func>(aFunc)(extract());
648 }
649 return *this;
650 }
651
652 template <typename Func>
653 constexpr Maybe& apply(Func&& aFunc) const&& {
654 if (isSome()) {
655 std::forward<Func>(aFunc)(extract());
656 }
657 return *this;
658 }
659
660 /*
661 * If |isSome()|, runs the provided function and returns the result wrapped
662 * in a Maybe. If |isNothing()|, returns an empty Maybe value with the same
663 * value type as what the provided function would have returned.
664 */
665 template <typename Func>
666 constexpr auto map(Func&& aFunc) & {
667 if (isSome()) {
668 return Some(std::forward<Func>(aFunc)(ref()));
669 }
670 return Maybe<decltype(std::forward<Func>(aFunc)(ref()))>{};
671 }
672
673 template <typename Func>
674 constexpr auto map(Func&& aFunc) const& {
675 if (isSome()) {
676 return Some(std::forward<Func>(aFunc)(ref()));
677 }
678 return Maybe<decltype(std::forward<Func>(aFunc)(ref()))>{};
679 }
680
681 template <typename Func>
682 constexpr auto map(Func&& aFunc) && {
683 if (isSome()) {
684 return Some(std::forward<Func>(aFunc)(extract()));
685 }
686 return Maybe<decltype(std::forward<Func>(aFunc)(extract()))>{};
687 }
688
689 template <typename Func>
690 constexpr auto map(Func&& aFunc) const&& {
691 if (isSome()) {
692 return Some(std::forward<Func>(aFunc)(extract()));
693 }
694 return Maybe<decltype(std::forward<Func>(aFunc)(extract()))>{};
695 }
696
697 /*
698 * If |isSome()|, runs the provided function or functor on the contents of
699 * this Maybe and returns the result. Note that the provided function or
700 * functor must return a Maybe<U> of any type U.
701 * If |isNothing()|, returns an empty Maybe value with the same type as what
702 * the provided function would have returned.
703 */
704 template <typename Func>
705 constexpr auto andThen(Func&& aFunc) & {
706 static_assert(std::is_invocable_v<Func, T&>);
707 using U = std::invoke_result_t<Func, T&>;
708 static_assert(detail::IsMaybe<U>::value);
709 if (isSome()) {
710 return std::invoke(std::forward<Func>(aFunc), ref());
711 }
712 return std::remove_cv_t<std::remove_reference_t<U>>{};
713 }
714
715 template <typename Func>
716 constexpr auto andThen(Func&& aFunc) const& {
717 static_assert(std::is_invocable_v<Func, const T&>);
718 using U = std::invoke_result_t<Func, const T&>;
719 static_assert(detail::IsMaybe<U>::value);
720 if (isSome()) {
721 return std::invoke(std::forward<Func>(aFunc), ref());
722 }
723 return std::remove_cv_t<std::remove_reference_t<U>>{};
724 }
725
726 template <typename Func>
727 constexpr auto andThen(Func&& aFunc) && {
728 static_assert(std::is_invocable_v<Func, T&&>);
729 using U = std::invoke_result_t<Func, T&&>;
730 static_assert(detail::IsMaybe<U>::value);
731 if (isSome()) {
732 return std::invoke(std::forward<Func>(aFunc), extract());
733 }
734 return std::remove_cv_t<std::remove_reference_t<U>>{};
735 }
736
737 template <typename Func>
738 constexpr auto andThen(Func&& aFunc) const&& {
739 static_assert(std::is_invocable_v<Func, const T&&>);
740 using U = std::invoke_result_t<Func, const T&&>;
741 static_assert(detail::IsMaybe<U>::value);
742 if (isSome()) {
743 return std::invoke(std::forward<Func>(aFunc), extract());
744 }
745 return std::remove_cv_t<std::remove_reference_t<U>>{};
746 }
747
748 /*
749 * If |isNothing()|, runs the provided function or functor and returns its
750 * result. If |isSome()|, returns the contained value wrapped in a Maybe.
751 */
752 template <typename Func>
753 constexpr Maybe orElse(Func&& aFunc) & {
754 static_assert(std::is_invocable_v<Func>);
755 using U = std::invoke_result_t<Func>;
756 static_assert(
757 std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
758 if (isSome()) {
759 return *this;
760 }
761 return std::invoke(std::forward<Func>(aFunc));
762 }
763
764 template <typename Func>
765 constexpr Maybe orElse(Func&& aFunc) const& {
766 static_assert(std::is_invocable_v<Func>);
767 using U = std::invoke_result_t<Func>;
768 static_assert(
769 std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
770 if (isSome()) {
771 return *this;
772 }
773 return std::invoke(std::forward<Func>(aFunc));
774 }
775
776 template <typename Func>
777 constexpr Maybe orElse(Func&& aFunc) && {
778 static_assert(std::is_invocable_v<Func>);
779 using U = std::invoke_result_t<Func>;
780 static_assert(
781 std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
782 if (isSome()) {
783 return std::move(*this);
784 }
785 return std::invoke(std::forward<Func>(aFunc));
786 }
787
788 template <typename Func>
789 constexpr Maybe orElse(Func&& aFunc) const&& {
790 static_assert(std::is_invocable_v<Func>);
791 using U = std::invoke_result_t<Func>;
792 static_assert(
793 std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
794 if (isSome()) {
795 return std::move(*this);
796 }
797 return std::invoke(std::forward<Func>(aFunc));
798 }
799
800 /* If |isSome()|, empties this Maybe and destroys its contents. */
801 constexpr void reset() {
802 if (isSome()) {
803 if constexpr (!std::is_trivially_destructible_v<T>) {
804 /*
805 * Static analyzer gets confused if we have Maybe<MutexAutoLock>,
806 * so we suppress thread-safety warnings here
807 */
808 MOZ_PUSH_IGNORE_THREAD_SAFETYGCC diagnostic push GCC diagnostic ignored "-Wthread-safety"
809 ref().T::~T();
810 MOZ_POP_THREAD_SAFETYGCC diagnostic pop
811 poisonData();
812 }
813 mIsSome = false;
814 }
815 }
816
817 /*
818 * Constructs a T value in-place in this empty Maybe<T>'s storage. The
819 * arguments to |emplace()| are the parameters to T's constructor.
820 */
821 template <typename... Args>
822 constexpr void emplace(Args&&... aArgs);
823
824 template <typename U>
825 constexpr std::enable_if_t<std::is_same_v<T, U> &&
826 std::is_copy_constructible_v<U> &&
827 !std::is_move_constructible_v<U>>
828 emplace(U&& aArgs) {
829 emplace(aArgs);
830 }
831
832 friend std::ostream& operator<<(std::ostream& aStream,
833 const Maybe<T>& aMaybe) {
834 if (aMaybe) {
835 aStream << aMaybe.ref();
836 } else {
837 aStream << "<Nothing>";
838 }
839 return aStream;
840 }
841};
842
843template <typename T>
844class Maybe<T&> {
845 public:
846 constexpr Maybe() = default;
847 constexpr MOZ_IMPLICIT Maybe(Nothing) {}
848
849 void emplace(T& aRef) { mValue = &aRef; }
850
851 /* Methods that check whether this Maybe contains a value */
852 constexpr explicit operator bool() const { return isSome(); }
853 constexpr bool isSome() const { return mValue; }
854 constexpr bool isNothing() const { return !mValue; }
855
856 T& ref() const {
857 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 857); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 857; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
858 return *mValue;
859 }
860
861 T* operator->() const { return &ref(); }
862 T& operator*() const { return ref(); }
863
864 // Deliberately not defining value and ptr accessors, as these may be
865 // confusing on a reference-typed Maybe.
866
867 // XXX Should we define refOr?
868
869 void reset() { mValue = nullptr; }
870
871 template <typename Func>
872 const Maybe& apply(Func&& aFunc) const {
873 if (isSome()) {
874 std::forward<Func>(aFunc)(ref());
875 }
876 return *this;
877 }
878
879 template <typename Func>
880 auto map(Func&& aFunc) const {
881 Maybe<decltype(std::forward<Func>(aFunc)(ref()))> val;
882 if (isSome()) {
883 val.emplace(std::forward<Func>(aFunc)(ref()));
884 }
885 return val;
886 }
887
888 template <typename Func>
889 constexpr auto andThen(Func&& aFunc) const {
890 static_assert(std::is_invocable_v<Func, T&>);
891 using U = std::invoke_result_t<Func, T&>;
892 static_assert(detail::IsMaybe<U>::value);
893 if (isSome()) {
894 return std::invoke(std::forward<Func>(aFunc), ref());
895 }
896 return std::remove_cv_t<std::remove_reference_t<U>>{};
897 }
898
899 template <typename Func>
900 constexpr Maybe orElse(Func&& aFunc) const {
901 static_assert(std::is_invocable_v<Func>);
902 using U = std::invoke_result_t<Func>;
903 static_assert(
904 std::is_same_v<Maybe, std::remove_cv_t<std::remove_reference_t<U>>>);
905 if (isSome()) {
906 return *this;
907 }
908 return std::invoke(std::forward<Func>(aFunc));
909 }
910
911 bool refEquals(const Maybe<T&>& aOther) const {
912 return mValue == aOther.mValue;
913 }
914
915 bool refEquals(const T& aOther) const { return mValue == &aOther; }
916
917 private:
918 T* mValue = nullptr;
919};
920
921template <typename T>
922constexpr T Maybe<T>::value() const& {
923 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 923); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 923; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
924 return ref();
925}
926
927template <typename T>
928constexpr T Maybe<T>::value() && {
929 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 929); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 929; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
930 return std::move(ref());
931}
932
933template <typename T>
934constexpr T Maybe<T>::value() const&& {
935 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 935); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 935; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
936 return std::move(ref());
937}
938
939template <typename T>
940T* Maybe<T>::ptr() {
941 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 941); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 941; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
942 return &ref();
943}
944
945template <typename T>
946constexpr const T* Maybe<T>::ptr() const {
947 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 947); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 947; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
948 return &ref();
949}
950
951template <typename T>
952constexpr T* Maybe<T>::operator->() {
953 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 953); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 953; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
954 return ptr();
955}
956
957template <typename T>
958constexpr const T* Maybe<T>::operator->() const {
959 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 959); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 959; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
960 return ptr();
961}
962
963template <typename T>
964constexpr T& Maybe<T>::ref() & {
965 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 965); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 965; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
966 return mStorage.val;
967}
968
969template <typename T>
970constexpr const T& Maybe<T>::ref() const& {
971 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 971); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 971; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
972 return mStorage.val;
973}
974
975template <typename T>
976constexpr T&& Maybe<T>::ref() && {
977 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 977); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 977; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
978 return std::move(mStorage.val);
979}
980
981template <typename T>
982constexpr const T&& Maybe<T>::ref() const&& {
983 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 983); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 983; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
984 return std::move(mStorage.val);
985}
986
987template <typename T>
988constexpr T& Maybe<T>::operator*() & {
989 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 989); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 989; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
990 return ref();
991}
992
993template <typename T>
994constexpr const T& Maybe<T>::operator*() const& {
995 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 995); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 995; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
996 return ref();
997}
998
999template <typename T>
1000constexpr T&& Maybe<T>::operator*() && {
1001 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 1001); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 1001; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1002 return std::move(ref());
1003}
1004
1005template <typename T>
1006constexpr const T&& Maybe<T>::operator*() const&& {
1007 MOZ_RELEASE_ASSERT(isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 1007); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "isSome()"
")"); do { *((volatile int*)__null) = 1007; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1008 return std::move(ref());
1009}
1010
1011template <typename T>
1012template <typename... Args>
1013constexpr void Maybe<T>::emplace(Args&&... aArgs) {
1014 MOZ_RELEASE_ASSERT(!isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!isSome()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!isSome()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/Maybe.h"
, 1014); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!isSome()"
")"); do { *((volatile int*)__null) = 1014; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1015 ::new (KnownNotNull, &mStorage.val) T(std::forward<Args>(aArgs)...);
1016 mIsSome = true;
1017}
1018
1019/*
1020 * Some() creates a Maybe<T> value containing the provided T value. If T has a
1021 * move constructor, it's used to make this as efficient as possible.
1022 *
1023 * Some() selects the type of Maybe it returns by removing any const, volatile,
1024 * or reference qualifiers from the type of the value you pass to it. This gives
1025 * it more intuitive behavior when used in expressions, but it also means that
1026 * if you need to construct a Maybe value that holds a const, volatile, or
1027 * reference value, you need to use emplace() instead.
1028 */
1029template <typename T, typename U>
1030constexpr Maybe<U> Some(T&& aValue) {
1031 return {std::forward<T>(aValue), typename Maybe<U>::SomeGuard{}};
1032}
1033
1034template <typename T>
1035constexpr Maybe<T&> SomeRef(T& aValue) {
1036 Maybe<T&> value;
1037 value.emplace(aValue);
1038 return value;
1039}
1040
1041template <typename T>
1042constexpr Maybe<T&> ToMaybeRef(T* const aPtr) {
1043 return aPtr ? SomeRef(*aPtr) : Nothing{};
1044}
1045
1046template <typename T>
1047Maybe<std::remove_cv_t<std::remove_reference_t<T>>> ToMaybe(T* aPtr) {
1048 if (aPtr) {
1049 return Some(*aPtr);
1050 }
1051 return Nothing();
1052}
1053
1054/*
1055 * Two Maybe<T> values are equal if
1056 * - both are Nothing, or
1057 * - both are Some, and the values they contain are equal.
1058 */
1059template <typename T>
1060constexpr bool operator==(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1061 static_assert(!std::is_reference_v<T>,
1062 "operator== is not defined for Maybe<T&>, compare values or "
1063 "addresses explicitly instead");
1064 if (aLHS.isNothing() != aRHS.isNothing()) {
1065 return false;
1066 }
1067 return aLHS.isNothing() || *aLHS == *aRHS;
1068}
1069
1070template <typename T>
1071constexpr bool operator!=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1072 return !(aLHS == aRHS);
1073}
1074
1075/*
1076 * We support comparison to Nothing to allow reasonable expressions like:
1077 * if (maybeValue == Nothing()) { ... }
1078 */
1079template <typename T>
1080constexpr bool operator==(const Maybe<T>& aLHS, const Nothing& aRHS) {
1081 return aLHS.isNothing();
1082}
1083
1084template <typename T>
1085constexpr bool operator!=(const Maybe<T>& aLHS, const Nothing& aRHS) {
1086 return !(aLHS == aRHS);
1087}
1088
1089template <typename T>
1090constexpr bool operator==(const Nothing& aLHS, const Maybe<T>& aRHS) {
1091 return aRHS.isNothing();
1092}
1093
1094template <typename T>
1095constexpr bool operator!=(const Nothing& aLHS, const Maybe<T>& aRHS) {
1096 return !(aLHS == aRHS);
1097}
1098
1099/*
1100 * Maybe<T> values are ordered in the same way T values are ordered, except that
1101 * Nothing comes before anything else.
1102 */
1103template <typename T>
1104constexpr bool operator<(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1105 if (aLHS.isNothing()) {
1106 return aRHS.isSome();
1107 }
1108 if (aRHS.isNothing()) {
1109 return false;
1110 }
1111 return *aLHS < *aRHS;
1112}
1113
1114template <typename T>
1115constexpr bool operator>(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1116 return !(aLHS < aRHS || aLHS == aRHS);
1117}
1118
1119template <typename T>
1120constexpr bool operator<=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1121 return aLHS < aRHS || aLHS == aRHS;
1122}
1123
1124template <typename T>
1125constexpr bool operator>=(const Maybe<T>& aLHS, const Maybe<T>& aRHS) {
1126 return !(aLHS < aRHS);
1127}
1128
1129template <typename T>
1130inline void ImplCycleCollectionTraverse(
1131 nsCycleCollectionTraversalCallback& aCallback, mozilla::Maybe<T>& aField,
1132 const char* aName, uint32_t aFlags = 0) {
1133 if (aField) {
1134 ImplCycleCollectionTraverse(aCallback, aField.ref(), aName, aFlags);
1135 }
1136}
1137
1138template <typename T>
1139inline void ImplCycleCollectionUnlink(mozilla::Maybe<T>& aField) {
1140 if (aField) {
1141 ImplCycleCollectionUnlink(aField.ref());
1142 }
1143}
1144
1145} // namespace mozilla
1146
1147#endif /* mozilla_Maybe_h */

/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/MaybeStorageBase.h

1/* -*- Mode: C++; tab-width: 2; 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/* Internal storage class used e.g. by Maybe and Result. This file doesn't
8 * contain any public declarations. */
9
10#ifndef mfbt_MaybeStorageBase_h
11#define mfbt_MaybeStorageBase_h
12
13#include <type_traits>
14#include <utility>
15
16namespace mozilla::detail {
17
18template <typename T>
19constexpr bool IsTriviallyDestructibleAndCopyable =
20 std::is_trivially_destructible_v<T> &&
21 (std::is_trivially_copy_constructible_v<T> ||
22 !std::is_copy_constructible_v<T>);
23
24template <typename T, bool TriviallyDestructibleAndCopyable =
25 IsTriviallyDestructibleAndCopyable<T>>
26struct MaybeStorageBase;
27
28template <typename T>
29struct MaybeStorageBase<T, false> {
30 protected:
31 using NonConstT = std::remove_const_t<T>;
32
33 union Union {
34 Union() {}
26
Returning without writing to 'this->val.mClickTarget.mRawPtr'
35 explicit Union(const T& aVal) : val{aVal} {}
36 template <typename U,
37 typename = std::enable_if_t<std::is_move_constructible_v<U>>>
38 explicit Union(U&& aVal) : val{std::forward<U>(aVal)} {}
39 template <typename... Args>
40 explicit Union(std::in_place_t, Args&&... aArgs)
41 : val{std::forward<Args>(aArgs)...} {}
42
43 ~Union() {}
46
Calling '~WidgetMouseEvent'
44
45 NonConstT val;
46 } mStorage;
47
48 public:
49 MaybeStorageBase() = default;
25
Calling default constructor for 'Union'
27
Returning from default constructor for 'Union'
28
Returning without writing to 'this->mStorage.val.mClickTarget.mRawPtr'
50 explicit MaybeStorageBase(const T& aVal) : mStorage{aVal} {}
51 explicit MaybeStorageBase(T&& aVal) : mStorage{std::move(aVal)} {}
52 template <typename... Args>
53 explicit MaybeStorageBase(std::in_place_t, Args&&... aArgs)
54 : mStorage{std::in_place, std::forward<Args>(aArgs)...} {}
55
56 const T* addr() const { return &mStorage.val; }
57 T* addr() { return &mStorage.val; }
58};
59
60template <typename T>
61struct MaybeStorageBase<T, true> {
62 protected:
63 using NonConstT = std::remove_const_t<T>;
64
65 union Union {
66 constexpr Union() : dummy() {}
67 constexpr explicit Union(const T& aVal) : val{aVal} {}
68 constexpr explicit Union(T&& aVal) : val{std::move(aVal)} {}
69 template <typename... Args>
70 constexpr explicit Union(std::in_place_t, Args&&... aArgs)
71 : val{std::forward<Args>(aArgs)...} {}
72
73 NonConstT val;
74 char dummy;
75 } mStorage;
76
77 public:
78 constexpr MaybeStorageBase() = default;
79 constexpr explicit MaybeStorageBase(const T& aVal) : mStorage{aVal} {}
80 constexpr explicit MaybeStorageBase(T&& aVal) : mStorage{std::move(aVal)} {}
81
82 template <typename... Args>
83 constexpr explicit MaybeStorageBase(std::in_place_t, Args&&... aArgs)
84 : mStorage{std::in_place, std::forward<Args>(aArgs)...} {}
85
86 constexpr const T* addr() const { return &mStorage.val; }
87 constexpr T* addr() { return &mStorage.val; }
88};
89
90} // namespace mozilla::detail
91
92#endif

/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/MemoryReportingProcess.h

1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#ifndef xpcom_base_MemoryReportingProcess_h
8#define xpcom_base_MemoryReportingProcess_h
9
10#include <stdint.h>
11#include "nscore.h"
12
13namespace mozilla {
14namespace ipc {
15class FileDescriptor;
16} // namespace ipc
17
18template <class T>
19class Maybe;
20
21// Top-level process actors should implement this to integrate with
22// nsMemoryReportManager.
23class MemoryReportingProcess {
24 public:
25 NS_IMETHOD_(MozExternalRefCountType)virtual MozExternalRefCountType AddRef() = 0;
26 NS_IMETHOD_(MozExternalRefCountType)virtual MozExternalRefCountType Release() = 0;
27
28 virtual ~MemoryReportingProcess() = default;
29
30 // Return true if the process is still alive, false otherwise.
31 virtual bool IsAlive() const = 0;
32
33 // Initiate a memory report request, returning true if a report was
34 // successfully initiated and false otherwise.
35 virtual bool SendRequestMemoryReport(
36 const uint32_t& aGeneration, const bool& aAnonymize,
37 const bool& aMinimizeMemoryUsage,
38 const Maybe<mozilla::ipc::FileDescriptor>& aDMDFile) = 0;
39
40 virtual int32_t Pid() const = 0;
41};
42
43} // namespace mozilla
44
45#endif // xpcom_base_MemoryReportingProcess_h

/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/MouseEvents.h

1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6#ifndef mozilla_MouseEvents_h__
7#define mozilla_MouseEvents_h__
8
9#include <stdint.h>
10#include <math.h>
11
12#include "mozilla/BasicEvents.h"
13#include "mozilla/EventForwards.h"
14#include "mozilla/MathAlgorithms.h"
15#include "mozilla/dom/DataTransfer.h"
16#include "mozilla/ipc/IPCForwards.h"
17#include "nsCOMPtr.h"
18
19namespace mozilla {
20
21namespace dom {
22class PBrowserParent;
23class PBrowserChild;
24class PBrowserBridgeParent;
25} // namespace dom
26
27class WidgetPointerEvent;
28} // namespace mozilla
29
30namespace mozilla {
31class WidgetPointerEventHolder final {
32 public:
33 nsTArray<WidgetPointerEvent> mEvents;
34 NS_INLINE_DECL_REFCOUNTING(WidgetPointerEventHolder)public: MozExternalRefCountType AddRef(void) { static_assert(
!std::is_destructible_v<WidgetPointerEventHolder>, "Reference-counted class "
"WidgetPointerEventHolder" " 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/obj-x86_64-pc-linux-gnu/dist/include/mozilla/MouseEvents.h"
, 34); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
34; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); _mOwningThread.AssertOwnership("WidgetPointerEventHolder"
" not thread-safe"); ++mRefCnt; NS_LogAddRef((this), (mRefCnt
), ("WidgetPointerEventHolder"), (uint32_t)(sizeof(*this))); return
mRefCnt; } MozExternalRefCountType 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/obj-x86_64-pc-linux-gnu/dist/include/mozilla/MouseEvents.h"
, 34); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 34
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); _mOwningThread.AssertOwnership("WidgetPointerEventHolder"
" not thread-safe"); --mRefCnt; NS_LogRelease((this), (mRefCnt
), ("WidgetPointerEventHolder")); if (mRefCnt == 0) { mRefCnt
= 1; delete (this); return 0; } return mRefCnt; } using HasThreadSafeRefCnt
= std::false_type; protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread
_mOwningThread; public:
35
36 private:
37 virtual ~WidgetPointerEventHolder() = default;
38};
39
40/******************************************************************************
41 * mozilla::WidgetPointerHelper
42 ******************************************************************************/
43
44class WidgetPointerHelper {
45 public:
46 uint32_t pointerId;
47 int32_t tiltX;
48 int32_t tiltY;
49 int32_t twist;
50 float tangentialPressure;
51 bool convertToPointer;
52 RefPtr<WidgetPointerEventHolder> mCoalescedWidgetEvents;
53
54 WidgetPointerHelper()
55 : pointerId(0),
56 tiltX(0),
57 tiltY(0),
58 twist(0),
59 tangentialPressure(0),
60 convertToPointer(true) {}
61
62 WidgetPointerHelper(uint32_t aPointerId, uint32_t aTiltX, uint32_t aTiltY,
63 uint32_t aTwist = 0, float aTangentialPressure = 0)
64 : pointerId(aPointerId),
65 tiltX(aTiltX),
66 tiltY(aTiltY),
67 twist(aTwist),
68 tangentialPressure(aTangentialPressure),
69 convertToPointer(true) {}
70
71 explicit WidgetPointerHelper(const WidgetPointerHelper& aHelper) = default;
72
73 constexpr static double kPi =
74#ifdef M_PI3.14159265358979323846
75 M_PI3.14159265358979323846;
76#else
77 3.14159265358979323846;
78#endif
79 constexpr static double kHalfPi =
80#ifdef M_PI_21.57079632679489661923
81 M_PI_21.57079632679489661923;
82#else
83 1.57079632679489661923;
84#endif
85 constexpr static double kDoublePi = kPi * 2;
86
87 constexpr static double GetDefaultAltitudeAngle() { return kHalfPi; }
88 constexpr static double GetDefaultAzimuthAngle() { return 0.0; }
89
90 double ComputeAltitudeAngle() const {
91 return ComputeAltitudeAngle(tiltX, tiltY);
92 }
93 double ComputeAzimuthAngle() const {
94 return ComputeAzimuthAngle(tiltX, tiltY);
95 }
96
97 static double ComputeAltitudeAngle(int32_t aTiltX, int32_t aTiltY);
98 static double ComputeAzimuthAngle(int32_t aTiltX, int32_t aTiltY);
99
100 static double ComputeTiltX(double aAltitudeAngle, double aAzimuthAngle);
101 static double ComputeTiltY(double aAltitudeAngle, double aAzimuthAngle);
102
103 void AssignPointerHelperData(const WidgetPointerHelper& aEvent,
104 bool aCopyCoalescedEvents = false) {
105 pointerId = aEvent.pointerId;
106 tiltX = aEvent.tiltX;
107 tiltY = aEvent.tiltY;
108 twist = aEvent.twist;
109 tangentialPressure = aEvent.tangentialPressure;
110 convertToPointer = aEvent.convertToPointer;
111 if (aCopyCoalescedEvents) {
112 mCoalescedWidgetEvents = aEvent.mCoalescedWidgetEvents;
113 }
114 }
115
116 private:
117 static int32_t GetValidTiltValue(int32_t aTilt);
118 static double GetValidAltitudeAngle(double aAltitudeAngle);
119 static double GetValidAzimuthAngle(double aAzimuthAngle);
120};
121
122/******************************************************************************
123 * mozilla::WidgetMouseEventBase
124 ******************************************************************************/
125
126class WidgetMouseEventBase : public WidgetInputEvent {
127 private:
128 friend class dom::PBrowserParent;
129 friend class dom::PBrowserChild;
130 friend class dom::PBrowserBridgeParent;
131 ALLOW_DEPRECATED_READPARAMpublic: enum { kHasDeprecatedReadParamPrivateConstructor = true
}; template <typename, bool> friend class IPC::ReadResult
; private:
132
133 protected:
134 WidgetMouseEventBase()
135 : mPressure(0),
136 mButton(0),
137 mButtons(0),
138 mInputSource(/* MouseEvent_Binding::MOZ_SOURCE_MOUSE = */ 1) {}
139 // Including MouseEventBinding.h here leads to an include loop, so
140 // we have to hardcode MouseEvent_Binding::MOZ_SOURCE_MOUSE.
141
142 WidgetMouseEventBase(bool aIsTrusted, EventMessage aMessage,
143 nsIWidget* aWidget, EventClassID aEventClassID,
144 const WidgetEventTime* aTime = nullptr)
145 : WidgetInputEvent(aIsTrusted, aMessage, aWidget, aEventClassID, aTime),
146 mPressure(0),
147 mButton(0),
148 mButtons(0),
149 mInputSource(/* MouseEvent_Binding::MOZ_SOURCE_MOUSE = */ 1) {}
150 // Including MouseEventBinding.h here leads to an include loop, so
151 // we have to hardcode MouseEvent_Binding::MOZ_SOURCE_MOUSE.
152
153 public:
154 virtual WidgetMouseEventBase* AsMouseEventBase() override { return this; }
155
156 virtual WidgetEvent* Duplicate() const override {
157 MOZ_CRASH("WidgetMouseEventBase must not be most-subclass")do { do { } while (false); MOZ_ReportCrash("" "WidgetMouseEventBase must not be most-subclass"
, "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/MouseEvents.h"
, 157); AnnotateMozCrashReason("MOZ_CRASH(" "WidgetMouseEventBase must not be most-subclass"
")"); do { *((volatile int*)__null) = 157; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
158 }
159
160 // Finger or touch pressure of event. It ranges between 0.0 and 1.0.
161 float mPressure;
162
163 // Pressed button ID of mousedown or mouseup event.
164 // This is set only when pressing a button causes the event.
165 int16_t mButton;
166
167 // Flags of all pressed buttons at the event fired.
168 // This is set at any mouse event, don't be confused with |mButton|.
169 int16_t mButtons;
170
171 // Possible values a in MouseEvent
172 uint16_t mInputSource;
173
174 bool IsLeftButtonPressed() const {
175 return !!(mButtons & MouseButtonsFlag::ePrimaryFlag);
176 }
177 bool IsRightButtonPressed() const {
178 return !!(mButtons & MouseButtonsFlag::eSecondaryFlag);
179 }
180 bool IsMiddleButtonPressed() const {
181 return !!(mButtons & MouseButtonsFlag::eMiddleFlag);
182 }
183 bool Is4thButtonPressed() const {
184 return !!(mButtons & MouseButtonsFlag::e4thFlag);
185 }
186 bool Is5thButtonPressed() const {
187 return !!(mButtons & MouseButtonsFlag::e5thFlag);
188 }
189
190 void AssignMouseEventBaseData(const WidgetMouseEventBase& aEvent,
191 bool aCopyTargets) {
192 AssignInputEventData(aEvent, aCopyTargets);
193
194 mButton = aEvent.mButton;
195 mButtons = aEvent.mButtons;
196 mPressure = aEvent.mPressure;
197 mInputSource = aEvent.mInputSource;
198 }
199
200 /**
201 * Returns true if left click event.
202 */
203 bool IsLeftClickEvent() const {
204 return mMessage == ePointerClick && mButton == MouseButton::ePrimary;
205 }
206
207 /**
208 * Returns true if this event changes a button state to "pressed".
209 */
210 [[nodiscard]] bool IsPressingButton() const {
211 MOZ_ASSERT(IsTrusted())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsTrusted())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsTrusted()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("IsTrusted()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/MouseEvents.h"
, 211); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTrusted()"
")"); do { *((volatile int*)__null) = 211; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
212 if (mClass == eMouseEventClass) {
213 return mMessage == eMouseDown;
214 }
215 if (mButton == MouseButton::eNotPressed) {
216 return false;
217 }
218 // If this is an ePointerDown event whose mButton is not "not pressed", this
219 // is a button pressing event.
220 if (mMessage == ePointerDown) {
221 return true;
222 }
223 // If 2 or more buttons are pressed at same time, they are sent with
224 // pointermove rather than pointerdown. Therefore, let's check whether
225 // mButtons contains the proper flag for the pressing button.
226 const bool buttonsContainButton = !!(
227 mButtons & MouseButtonsFlagToChange(static_cast<MouseButton>(mButton)));
228 return mMessage == ePointerMove && buttonsContainButton;
229 }
230
231 /**
232 * Returns true if this event changes a button state to "released".
233 */
234 [[nodiscard]] bool IsReleasingButton() const {
235 MOZ_ASSERT(IsTrusted())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsTrusted())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsTrusted()))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("IsTrusted()", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/MouseEvents.h"
, 235); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsTrusted()"
")"); do { *((volatile int*)__null) = 235; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
236 if (mClass == eMouseEventClass) {
237 return mMessage == eMouseUp;
238 }
239 if (mButton == MouseButton::eNotPressed) {
240 return false;
241 }
242 // If this is an ePointerUp event whose mButton is not "not pressed", this
243 // is a button release event.
244 if (mMessage == ePointerUp) {
245 return true;
246 }
247 // If the releasing button is not the last button of pressing buttons, web
248 // apps notified by pointermove rather than pointerup. Therefore, let's
249 // check whether mButtons loses the proper flag for the releasing button.
250 const bool buttonsLoseTheButton = !(
251 mButtons & MouseButtonsFlagToChange(static_cast<MouseButton>(mButton)));
252 return mMessage == ePointerMove && buttonsLoseTheButton;
253 }
254
255 /**
256 * Returns true if the input source supports hover state like a mouse.
257 */
258 [[nodiscard]] bool InputSourceSupportsHover() const;
259};
260
261/******************************************************************************
262 * mozilla::WidgetMouseEvent
263 ******************************************************************************/
264
265class WidgetMouseEvent : public WidgetMouseEventBase,
266 public WidgetPointerHelper {
267 private:
268 friend class dom::PBrowserParent;
269 friend class dom::PBrowserChild;
270 friend class dom::PBrowserBridgeParent;
271 ALLOW_DEPRECATED_READPARAMpublic: enum { kHasDeprecatedReadParamPrivateConstructor = true
}; template <typename, bool> friend class IPC::ReadResult
; private:
272
273 public:
274 typedef bool ReasonType;
275 enum Reason : ReasonType { eReal, eSynthesized };
276
277 typedef uint8_t ContextMenuTriggerType;
278 enum ContextMenuTrigger : ContextMenuTriggerType {
279 eNormal,
280 eContextMenuKey,
281 eControlClick
282 };
283
284 typedef uint8_t ExitFromType;
285 enum ExitFrom : ExitFromType {
286 ePlatformChild,
287 ePlatformTopLevel,
288 ePuppet,
289 ePuppetParentToPuppetChild
290 };
291
292 protected:
293 WidgetMouseEvent() = default;
294
295 WidgetMouseEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget,
296 EventClassID aEventClassID, Reason aReason,
297 ContextMenuTrigger aContextMenuTrigger,
298 const WidgetEventTime* aTime = nullptr)
299 : WidgetMouseEventBase(aIsTrusted, aMessage, aWidget, aEventClassID,
300 aTime),
301 mReason(aReason),
302 mContextMenuTrigger(aContextMenuTrigger) {}
303
304#ifdef DEBUG1
305 void AssertContextMenuEventButtonConsistency() const;
306#endif
307
308 public:
309 virtual WidgetMouseEvent* AsMouseEvent() override { return this; }
310
311 WidgetMouseEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget,
312 Reason aReason = eReal,
313 ContextMenuTrigger aContextMenuTrigger = eNormal,
314 const WidgetEventTime* aTime = nullptr)
315 : WidgetMouseEventBase(aIsTrusted, aMessage, aWidget, eMouseEventClass,
316 aTime),
317 mReason(aReason),
318 mContextMenuTrigger(aContextMenuTrigger) {
319 MOZ_ASSERT_IF(aIsTrusted, !IsPointerEventMessage(mMessage))do { if (aIsTrusted) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(!IsPointerEventMessage(mMessage))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsPointerEventMessage(mMessage
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!IsPointerEventMessage(mMessage)", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/MouseEvents.h"
, 319); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsPointerEventMessage(mMessage)"
")"); do { *((volatile int*)__null) = 319; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
320 if (aMessage == eContextMenu) {
321 mButton = (mContextMenuTrigger == eNormal) ? MouseButton::eSecondary
322 : MouseButton::ePrimary;
323 }
324 }
325
326#ifdef DEBUG1
327 virtual ~WidgetMouseEvent() { AssertContextMenuEventButtonConsistency(); }
47
Calling '~nsCOMPtr'
328#endif
329
330 virtual WidgetEvent* Duplicate() const override {
331 MOZ_ASSERT(mClass == eMouseEventClass,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mClass == eMouseEventClass)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mClass == eMouseEventClass))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mClass == eMouseEventClass"
" (" "Duplicate() must be overridden by sub class" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/MouseEvents.h"
, 332); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClass == eMouseEventClass"
") (" "Duplicate() must be overridden by sub class" ")"); do
{ *((volatile int*)__null) = 332; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
332 "Duplicate() must be overridden by sub class")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mClass == eMouseEventClass)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mClass == eMouseEventClass))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mClass == eMouseEventClass"
" (" "Duplicate() must be overridden by sub class" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/MouseEvents.h"
, 332); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClass == eMouseEventClass"
") (" "Duplicate() must be overridden by sub class" ")"); do
{ *((volatile int*)__null) = 332; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
333 // Not copying widget, it is a weak reference.
334 WidgetMouseEvent* result = new WidgetMouseEvent(
335 false, mMessage, nullptr, mReason, mContextMenuTrigger, this);
336 result->AssignMouseEventData(*this, true);
337 result->mFlags = mFlags;
338 return result;
339 }
340
341 // If during mouseup handling we detect that click event might need to be
342 // dispatched, this is setup to be the target of the click event.
343 nsCOMPtr<dom::EventTarget> mClickTarget;
344
345 // mReason indicates the reason why the event is fired:
346 // - Representing mouse operation.
347 // - Synthesized for emulating mousemove event when the content under the
348 // mouse cursor is scrolled.
349 Reason mReason = eReal;
350
351 // mContextMenuTrigger is valid only when mMessage is eContextMenu.
352 // This indicates if the context menu event is caused by context menu key or
353 // other reasons (typically, a click of right mouse button).
354 ContextMenuTrigger mContextMenuTrigger = eNormal;
355
356 // mExitFrom contains a value only when mMessage is eMouseExitFromWidget.
357 // This indicates if the mouse cursor exits from a top level platform widget,
358 // a child widget or a puppet widget.
359 Maybe<ExitFrom> mExitFrom;
360
361 // mClickCount may be non-zero value when mMessage is eMouseDown, eMouseUp,
362 // ePointerClick or eMouseDoubleClick. The number is count of mouse clicks.
363 // Otherwise, this must be 0.
364 uint32_t mClickCount = 0;
365
366 // Whether the event should ignore scroll frame bounds during dispatch.
367 bool mIgnoreRootScrollFrame = false;
368
369 // Whether the event should be dispatched on a target limited in capturing
370 // content.
371 bool mIgnoreCapturingContent = false;
372
373 // Whether the event shouldn't cause click event.
374 bool mClickEventPrevented = false;
375
376 // If this is set to true while the event is being dispatched,
377 // PresShell::EventHandler::FinalizeHandlingEvent will dispatch a synthesized
378 // eMouseMove or ePointerMove.
379 bool mSynthesizeMoveAfterDispatch = false;
380
381 void AssignMouseEventData(const WidgetMouseEvent& aEvent, bool aCopyTargets) {
382 AssignMouseEventBaseData(aEvent, aCopyTargets);
383 AssignPointerHelperData(aEvent, /* aCopyCoalescedEvents */ true);
384
385 mReason = aEvent.mReason;
386 mContextMenuTrigger = aEvent.mContextMenuTrigger;
387 mExitFrom = aEvent.mExitFrom;
388 mClickCount = aEvent.mClickCount;
389 mIgnoreRootScrollFrame = aEvent.mIgnoreRootScrollFrame;
390 mIgnoreCapturingContent = aEvent.mIgnoreCapturingContent;
391 mClickEventPrevented = aEvent.mClickEventPrevented;
392 }
393
394 /**
395 * Returns true if the event is a context menu event caused by key.
396 */
397 bool IsContextMenuKeyEvent() const {
398 return mMessage == eContextMenu && mContextMenuTrigger == eContextMenuKey;
399 }
400
401 /**
402 * Returns true if the event is a real mouse event. Otherwise, i.e., it's
403 * a synthesized event by scroll or something, returns false.
404 */
405 bool IsReal() const { return mReason == eReal; }
406
407 /**
408 * Returns true if middle click paste is enabled.
409 */
410 static bool IsMiddleClickPasteEnabled();
411};
412
413/******************************************************************************
414 * mozilla::WidgetDragEvent
415 ******************************************************************************/
416
417class WidgetDragEvent : public WidgetMouseEvent {
418 private:
419 friend class mozilla::dom::PBrowserParent;
420 friend class mozilla::dom::PBrowserChild;
421 ALLOW_DEPRECATED_READPARAMpublic: enum { kHasDeprecatedReadParamPrivateConstructor = true
}; template <typename, bool> friend class IPC::ReadResult
; private:
422
423 protected:
424 WidgetDragEvent()
425 : mUserCancelled(false),
426 mDefaultPreventedOnContent(false),
427 mInHTMLEditorEventListener(false) {}
428
429 public:
430 virtual WidgetDragEvent* AsDragEvent() override { return this; }
431
432 WidgetDragEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget,
433 const WidgetEventTime* aTime = nullptr)
434 : WidgetMouseEvent(aIsTrusted, aMessage, aWidget, eDragEventClass, eReal,
435 eNormal, aTime),
436 mUserCancelled(false),
437 mDefaultPreventedOnContent(false),
438 mInHTMLEditorEventListener(false) {}
439
440 virtual WidgetEvent* Duplicate() const override {
441 MOZ_ASSERT(mClass == eDragEventClass,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mClass == eDragEventClass)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mClass == eDragEventClass)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("mClass == eDragEventClass"
" (" "Duplicate() must be overridden by sub class" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/MouseEvents.h"
, 442); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClass == eDragEventClass"
") (" "Duplicate() must be overridden by sub class" ")"); do
{ *((volatile int*)__null) = 442; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
442 "Duplicate() must be overridden by sub class")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mClass == eDragEventClass)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mClass == eDragEventClass)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("mClass == eDragEventClass"
" (" "Duplicate() must be overridden by sub class" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/MouseEvents.h"
, 442); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClass == eDragEventClass"
") (" "Duplicate() must be overridden by sub class" ")"); do
{ *((volatile int*)__null) = 442; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
443 // Not copying widget, it is a weak reference.
444 WidgetDragEvent* result =
445 new WidgetDragEvent(false, mMessage, nullptr, this);
446 result->AssignDragEventData(*this, true);
447 result->mFlags = mFlags;
448 return result;
449 }
450
451 // The dragging data.
452 nsCOMPtr<dom::DataTransfer> mDataTransfer;
453
454 // If this is true, user has cancelled the drag operation.
455 bool mUserCancelled;
456 // If this is true, the drag event's preventDefault() is called on content.
457 bool mDefaultPreventedOnContent;
458 // If this event is currently being handled by HTMLEditorEventListener.
459 bool mInHTMLEditorEventListener;
460
461 // XXX Not tested by test_assign_event_data.html
462 void AssignDragEventData(const WidgetDragEvent& aEvent, bool aCopyTargets) {
463 AssignMouseEventData(aEvent, aCopyTargets);
464
465 mDataTransfer = aEvent.mDataTransfer;
466 // XXX mUserCancelled isn't copied, is this intentionally?
467 mUserCancelled = false;
468 mDefaultPreventedOnContent = aEvent.mDefaultPreventedOnContent;
469 // XXX mInHTMLEditorEventListener isn't copied, is this intentionally?
470 mInHTMLEditorEventListener = false;
471 }
472
473 bool CanConvertToInputData() const {
474 return mMessage == eDragStart || mMessage == eDragEnd;
475 }
476
477 /**
478 * Should be called before dispatching the DOM tree if this event is
479 * synthesized for tests because drop effect is initialized before
480 * dispatching from widget if it's not synthesized event, but synthesized
481 * events are not initialized in the path.
482 */
483 void InitDropEffectForTests();
484};
485
486/******************************************************************************
487 * mozilla::WidgetMouseScrollEvent
488 *
489 * This is used for legacy DOM mouse scroll events, i.e.,
490 * DOMMouseScroll and MozMousePixelScroll event. These events are NOT hanbled
491 * by ESM even if widget dispatches them. Use new WidgetWheelEvent instead.
492 ******************************************************************************/
493
494class WidgetMouseScrollEvent : public WidgetMouseEventBase {
495 private:
496 WidgetMouseScrollEvent() : mDelta(0), mIsHorizontal(false) {}
497
498 public:
499 virtual WidgetMouseScrollEvent* AsMouseScrollEvent() override { return this; }
500
501 WidgetMouseScrollEvent(bool aIsTrusted, EventMessage aMessage,
502 nsIWidget* aWidget,
503 const WidgetEventTime* aTime = nullptr)
504 : WidgetMouseEventBase(aIsTrusted, aMessage, aWidget,
505 eMouseScrollEventClass, aTime),
506 mDelta(0),
507 mIsHorizontal(false) {}
508
509 virtual WidgetEvent* Duplicate() const override {
510 MOZ_ASSERT(mClass == eMouseScrollEventClass,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mClass == eMouseScrollEventClass)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mClass == eMouseScrollEventClass
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mClass == eMouseScrollEventClass" " (" "Duplicate() must be overridden by sub class"
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/MouseEvents.h"
, 511); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClass == eMouseScrollEventClass"
") (" "Duplicate() must be overridden by sub class" ")"); do
{ *((volatile int*)__null) = 511; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
511 "Duplicate() must be overridden by sub class")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mClass == eMouseScrollEventClass)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mClass == eMouseScrollEventClass
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mClass == eMouseScrollEventClass" " (" "Duplicate() must be overridden by sub class"
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/MouseEvents.h"
, 511); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClass == eMouseScrollEventClass"
") (" "Duplicate() must be overridden by sub class" ")"); do
{ *((volatile int*)__null) = 511; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
512 // Not copying widget, it is a weak reference.
513 WidgetMouseScrollEvent* result =
514 new WidgetMouseScrollEvent(false, mMessage, nullptr, this);
515 result->AssignMouseScrollEventData(*this, true);
516 result->mFlags = mFlags;
517 return result;
518 }
519
520 // The delta value of mouse scroll event.
521 // If the event message is eLegacyMouseLineOrPageScroll, the value indicates
522 // scroll amount in lines. However, if the value is
523 // UIEvent::SCROLL_PAGE_UP or UIEvent::SCROLL_PAGE_DOWN, the
524 // value inducates one page scroll. If the event message is
525 // eLegacyMousePixelScroll, the value indicates scroll amount in pixels.
526 int32_t mDelta;
527
528 // If this is true, it may cause to scroll horizontally.
529 // Otherwise, vertically.
530 bool mIsHorizontal;
531
532 void AssignMouseScrollEventData(const WidgetMouseScrollEvent& aEvent,
533 bool aCopyTargets) {
534 AssignMouseEventBaseData(aEvent, aCopyTargets);
535
536 mDelta = aEvent.mDelta;
537 mIsHorizontal = aEvent.mIsHorizontal;
538 }
539};
540
541/******************************************************************************
542 * mozilla::WidgetWheelEvent
543 ******************************************************************************/
544
545class WidgetWheelEvent : public WidgetMouseEventBase {
546 private:
547 friend class mozilla::dom::PBrowserParent;
548 friend class mozilla::dom::PBrowserChild;
549 ALLOW_DEPRECATED_READPARAMpublic: enum { kHasDeprecatedReadParamPrivateConstructor = true
}; template <typename, bool> friend class IPC::ReadResult
; private:
550
551 WidgetWheelEvent()
552 : mDeltaX(0.0),
553 mDeltaY(0.0),
554 mDeltaZ(0.0),
555 mOverflowDeltaX(0.0),
556 mOverflowDeltaY(0.0)
557 // Including WheelEventBinding.h here leads to an include loop, so
558 // we have to hardcode WheelEvent_Binding::DOM_DELTA_PIXEL.
559 ,
560 mDeltaMode(/* WheelEvent_Binding::DOM_DELTA_PIXEL = */ 0),
561 mLineOrPageDeltaX(0),
562 mLineOrPageDeltaY(0),
563 mScrollType(SCROLL_DEFAULT),
564 mCustomizedByUserPrefs(false),
565 mMayHaveMomentum(false),
566 mIsMomentum(false),
567 mIsNoLineOrPageDelta(false),
568 mViewPortIsOverscrolled(false),
569 mCanTriggerSwipe(false),
570 mAllowToOverrideSystemScrollSpeed(false),
571 mDeltaValuesHorizontalizedForDefaultHandler(false) {}
572
573 public:
574 virtual WidgetWheelEvent* AsWheelEvent() override { return this; }
575
576 WidgetWheelEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget,
577 const WidgetEventTime* aTime = nullptr)
578 : WidgetMouseEventBase(aIsTrusted, aMessage, aWidget, eWheelEventClass,
579 aTime),
580 mDeltaX(0.0),
581 mDeltaY(0.0),
582 mDeltaZ(0.0),
583 mOverflowDeltaX(0.0),
584 mOverflowDeltaY(0.0)
585 // Including WheelEventBinding.h here leads to an include loop, so
586 // we have to hardcode WheelEvent_Binding::DOM_DELTA_PIXEL.
587 ,
588 mDeltaMode(/* WheelEvent_Binding::DOM_DELTA_PIXEL = */ 0),
589 mLineOrPageDeltaX(0),
590 mLineOrPageDeltaY(0),
591 mScrollType(SCROLL_DEFAULT),
592 mCustomizedByUserPrefs(false),
593 mMayHaveMomentum(false),
594 mIsMomentum(false),
595 mIsNoLineOrPageDelta(false),
596 mViewPortIsOverscrolled(false),
597 mCanTriggerSwipe(false),
598 mAllowToOverrideSystemScrollSpeed(true),
599 mDeltaValuesHorizontalizedForDefaultHandler(false) {}
600
601 virtual WidgetEvent* Duplicate() const override {
602 MOZ_ASSERT(mClass == eWheelEventClass,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mClass == eWheelEventClass)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mClass == eWheelEventClass))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mClass == eWheelEventClass"
" (" "Duplicate() must be overridden by sub class" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/MouseEvents.h"
, 603); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClass == eWheelEventClass"
") (" "Duplicate() must be overridden by sub class" ")"); do
{ *((volatile int*)__null) = 603; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
603 "Duplicate() must be overridden by sub class")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mClass == eWheelEventClass)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mClass == eWheelEventClass))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mClass == eWheelEventClass"
" (" "Duplicate() must be overridden by sub class" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/MouseEvents.h"
, 603); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClass == eWheelEventClass"
") (" "Duplicate() must be overridden by sub class" ")"); do
{ *((volatile int*)__null) = 603; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
604 // Not copying widget, it is a weak reference.
605 WidgetWheelEvent* result =
606 new WidgetWheelEvent(false, mMessage, nullptr, this);
607 result->AssignWheelEventData(*this, true);
608 result->mFlags = mFlags;
609 return result;
610 }
611
612 // Scroll gestures that start at the edge of the scrollable range can result
613 // in a swipe gesture. For the first wheel event of such a gesture, call
614 // TriggersSwipe() after the event has been processed in order to find out
615 // whether a swipe should be started.
616 bool TriggersSwipe() const {
617 return mCanTriggerSwipe && mViewPortIsOverscrolled &&
618 this->mOverflowDeltaX != 0.0;
619 }
620
621 // NOTE: mDeltaX, mDeltaY and mDeltaZ may be customized by
622 // mousewheel.*.delta_multiplier_* prefs which are applied by
623 // EventStateManager. So, after widget dispatches this event,
624 // these delta values may have different values than before.
625 double mDeltaX;
626 double mDeltaY;
627 double mDeltaZ;
628
629 // The mousewheel tick counts.
630 double mWheelTicksX = 0.0;
631 double mWheelTicksY = 0.0;
632
633 enum class DeltaModeCheckingState : uint8_t {
634 // Neither deltaMode nor the delta values have been accessed.
635 Unknown,
636 // The delta values have been accessed, without checking deltaMode first.
637 Unchecked,
638 // The deltaMode has been checked.
639 Checked,
640 };
641
642 // For compat reasons, we might expose a DOM_DELTA_LINE event as
643 // DOM_DELTA_PIXEL instead. Whether we do that depends on whether the event
644 // has been asked for the deltaMode before the deltas. If it has, we assume
645 // that the page will correctly handle DOM_DELTA_LINE. This variable tracks
646 // that state. See bug 1392460.
647 DeltaModeCheckingState mDeltaModeCheckingState =
648 DeltaModeCheckingState::Unknown;
649
650 // The amount of scrolling per line or page, without accounting for mouse
651 // wheel transactions etc.
652 //
653 // Computed by EventStateManager::DeltaAccumulator::InitLineOrPageDelta.
654 nsSize mScrollAmount;
655
656 // overflowed delta values for scroll, these values are set by
657 // EventStateManger. If the default action of the wheel event isn't scroll,
658 // these values are always zero. Otherwise, remaining delta values which are
659 // not used by scroll are set.
660 // NOTE: mDeltaX, mDeltaY and mDeltaZ may be modified by EventStateManager.
661 // However, mOverflowDeltaX and mOverflowDeltaY indicate unused original
662 // delta values which are not applied the delta_multiplier prefs.
663 // So, if widget wanted to know the actual direction to be scrolled,
664 // it would need to check the mDeltaX and mDeltaY.
665 double mOverflowDeltaX;
666 double mOverflowDeltaY;
667
668 // Should be one of WheelEvent_Binding::DOM_DELTA_*
669 uint32_t mDeltaMode;
670
671 // If widget sets mLineOrPageDelta, EventStateManager will dispatch
672 // eLegacyMouseLineOrPageScroll event for compatibility. Note that the delta
673 // value means pages if the mDeltaMode is DOM_DELTA_PAGE, otherwise, lines.
674 int32_t mLineOrPageDeltaX;
675 int32_t mLineOrPageDeltaY;
676
677 // When the default action for an wheel event is moving history or zooming,
678 // need to chose a delta value for doing it.
679 int32_t GetPreferredIntDelta() {
680 if (!mLineOrPageDeltaX && !mLineOrPageDeltaY) {
681 return 0;
682 }
683 if (mLineOrPageDeltaY && !mLineOrPageDeltaX) {
684 return mLineOrPageDeltaY;
685 }
686 if (mLineOrPageDeltaX && !mLineOrPageDeltaY) {
687 return mLineOrPageDeltaX;
688 }
689 if ((mLineOrPageDeltaX < 0 && mLineOrPageDeltaY > 0) ||
690 (mLineOrPageDeltaX > 0 && mLineOrPageDeltaY < 0)) {
691 return 0; // We cannot guess the answer in this case.
692 }
693 return (Abs(mLineOrPageDeltaX) > Abs(mLineOrPageDeltaY))
694 ? mLineOrPageDeltaX
695 : mLineOrPageDeltaY;
696 }
697
698 // Scroll type
699 // The default value is SCROLL_DEFAULT, which means EventStateManager will
700 // select preferred scroll type automatically.
701 enum ScrollType : uint8_t {
702 SCROLL_DEFAULT,
703 SCROLL_SYNCHRONOUSLY,
704 SCROLL_ASYNCHRONOUSLY,
705 SCROLL_SMOOTHLY
706 };
707 ScrollType mScrollType;
708
709 // If the delta values are computed from prefs, this value is true.
710 // Otherwise, i.e., they are computed from native events, false.
711 bool mCustomizedByUserPrefs;
712
713 // true if the momentum events directly tied to this event may follow it.
714 bool mMayHaveMomentum;
715 // true if the event is caused by momentum.
716 bool mIsMomentum;
717
718 // If device event handlers don't know when they should set mLineOrPageDeltaX
719 // and mLineOrPageDeltaY, this is true. Otherwise, false.
720 // If mIsNoLineOrPageDelta is true, ESM will generate
721 // eLegacyMouseLineOrPageScroll events when accumulated delta values reach
722 // a line height.
723 bool mIsNoLineOrPageDelta;
724
725 // Whether or not the parent of the currently overscrolled frame is the
726 // ViewPort. This is false in situations when an element on the page is being
727 // overscrolled (such as a text field), but true when the 'page' is being
728 // overscrolled.
729 bool mViewPortIsOverscrolled;
730
731 // The wheel event can trigger a swipe to start if it's overscrolling the
732 // viewport.
733 bool mCanTriggerSwipe;
734
735 // If mAllowToOverrideSystemScrollSpeed is true, the scroll speed may be
736 // overridden. Otherwise, the scroll speed won't be overridden even if
737 // it's enabled by the pref.
738 bool mAllowToOverrideSystemScrollSpeed;
739
740 // After the event's default action handler has adjusted its delta's values
741 // for horizontalizing a vertical wheel scroll, this variable will be set to
742 // true.
743 bool mDeltaValuesHorizontalizedForDefaultHandler;
744
745 void AssignWheelEventData(const WidgetWheelEvent& aEvent, bool aCopyTargets) {
746 AssignMouseEventBaseData(aEvent, aCopyTargets);
747
748 mDeltaX = aEvent.mDeltaX;
749 mDeltaY = aEvent.mDeltaY;
750 mDeltaZ = aEvent.mDeltaZ;
751 mDeltaMode = aEvent.mDeltaMode;
752 mScrollAmount = aEvent.mScrollAmount;
753 mCustomizedByUserPrefs = aEvent.mCustomizedByUserPrefs;
754 mMayHaveMomentum = aEvent.mMayHaveMomentum;
755 mIsMomentum = aEvent.mIsMomentum;
756 mIsNoLineOrPageDelta = aEvent.mIsNoLineOrPageDelta;
757 mLineOrPageDeltaX = aEvent.mLineOrPageDeltaX;
758 mLineOrPageDeltaY = aEvent.mLineOrPageDeltaY;
759 mScrollType = aEvent.mScrollType;
760 mOverflowDeltaX = aEvent.mOverflowDeltaX;
761 mOverflowDeltaY = aEvent.mOverflowDeltaY;
762 mViewPortIsOverscrolled = aEvent.mViewPortIsOverscrolled;
763 mCanTriggerSwipe = aEvent.mCanTriggerSwipe;
764 mAllowToOverrideSystemScrollSpeed =
765 aEvent.mAllowToOverrideSystemScrollSpeed;
766 mDeltaValuesHorizontalizedForDefaultHandler =
767 aEvent.mDeltaValuesHorizontalizedForDefaultHandler;
768 }
769
770 // System scroll speed settings may be too slow at using Gecko. In such
771 // case, we should override the scroll speed computed with system settings.
772 // Following methods return preferred delta values which are multiplied by
773 // factors specified by prefs. If system scroll speed shouldn't be
774 // overridden (e.g., this feature is disabled by pref), they return raw
775 // delta values.
776 double OverriddenDeltaX() const;
777 double OverriddenDeltaY() const;
778
779 // Compute the overridden delta value. This may be useful for suppressing
780 // too fast scroll by system scroll speed overriding when widget sets
781 // mAllowToOverrideSystemScrollSpeed.
782 static double ComputeOverriddenDelta(double aDelta, bool aIsForVertical);
783
784 private:
785 static bool sInitialized;
786 static bool sIsSystemScrollSpeedOverrideEnabled;
787 static int32_t sOverrideFactorX;
788 static int32_t sOverrideFactorY;
789 static void Initialize();
790};
791
792/******************************************************************************
793 * mozilla::WidgetPointerEvent
794 ******************************************************************************/
795
796class WidgetPointerEvent : public WidgetMouseEvent {
797 friend class mozilla::dom::PBrowserParent;
798 friend class mozilla::dom::PBrowserChild;
799 ALLOW_DEPRECATED_READPARAMpublic: enum { kHasDeprecatedReadParamPrivateConstructor = true
}; template <typename, bool> friend class IPC::ReadResult
; private:
800
801 WidgetPointerEvent() = default;
802
803 public:
804 virtual WidgetPointerEvent* AsPointerEvent() override { return this; }
805
806 WidgetPointerEvent(bool aIsTrusted, EventMessage aMsg, nsIWidget* w,
807 const WidgetEventTime* aTime)
808 : WidgetMouseEvent(aIsTrusted, aMsg, w, ePointerEventClass, eReal,
809 eNormal, aTime) {
810 if (aMsg == eContextMenu) {
811 mButton = (mContextMenuTrigger == eNormal) ? MouseButton::eSecondary
812 : MouseButton::ePrimary;
813 }
814 }
815
816 WidgetPointerEvent(bool aIsTrusted, EventMessage aMsg, nsIWidget* w,
817 ContextMenuTrigger aContextMenuTrigger = eNormal,
818 const WidgetEventTime* aTime = nullptr)
819 : WidgetMouseEvent(aIsTrusted, aMsg, w, ePointerEventClass, eReal,
820 aContextMenuTrigger, aTime) {
821 if (aMsg == eContextMenu) {
822 mButton = (mContextMenuTrigger == eNormal) ? MouseButton::eSecondary
823 : MouseButton::ePrimary;
824 }
825 }
826
827 explicit WidgetPointerEvent(const WidgetMouseEvent& aEvent)
828 : WidgetMouseEvent(aEvent) {
829 mClass = ePointerEventClass;
830 }
831
832 virtual WidgetEvent* Duplicate() const override {
833 MOZ_ASSERT(mClass == ePointerEventClass,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mClass == ePointerEventClass)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mClass == ePointerEventClass
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mClass == ePointerEventClass" " (" "Duplicate() must be overridden by sub class"
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/MouseEvents.h"
, 834); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClass == ePointerEventClass"
") (" "Duplicate() must be overridden by sub class" ")"); do
{ *((volatile int*)__null) = 834; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
834 "Duplicate() must be overridden by sub class")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mClass == ePointerEventClass)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mClass == ePointerEventClass
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mClass == ePointerEventClass" " (" "Duplicate() must be overridden by sub class"
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/MouseEvents.h"
, 834); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClass == ePointerEventClass"
") (" "Duplicate() must be overridden by sub class" ")"); do
{ *((volatile int*)__null) = 834; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
835 // Not copying widget, it is a weak reference.
836 WidgetPointerEvent* result = new WidgetPointerEvent(
837 false, mMessage, nullptr, mContextMenuTrigger, this);
838 result->AssignPointerEventData(*this, true);
839 result->mFlags = mFlags;
840 return result;
841 }
842
843 int32_t mWidth = 1;
844 int32_t mHeight = 1;
845 bool mIsPrimary = true;
846 bool mFromTouchEvent = false;
847
848 // XXX Not tested by test_assign_event_data.html
849 void AssignPointerEventData(const WidgetPointerEvent& aEvent,
850 bool aCopyTargets) {
851 AssignMouseEventData(aEvent, aCopyTargets);
852
853 mWidth = aEvent.mWidth;
854 mHeight = aEvent.mHeight;
855 mIsPrimary = aEvent.mIsPrimary;
856 mFromTouchEvent = aEvent.mFromTouchEvent;
857 }
858};
859
860} // namespace mozilla
861
862#endif // mozilla_MouseEvents_h__

/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsCOMPtr.h

1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#ifndef nsCOMPtr_h___
8#define nsCOMPtr_h___
9
10/*
11 * Having problems?
12 *
13 * See the documentation at:
14 * https://firefox-source-docs.mozilla.org/xpcom/refptr.html
15 *
16 *
17 * nsCOMPtr
18 * better than a raw pointer
19 * for owning objects
20 * -- scc
21 */
22
23#include <type_traits>
24
25#include "mozilla/AlreadyAddRefed.h"
26#include "mozilla/Assertions.h"
27#include "mozilla/Attributes.h"
28#include "mozilla/RefPtr.h"
29#include "nsCycleCollectionNoteChild.h"
30#include "nsDebug.h" // for |NS_ASSERTION|
31#include "nsISupportsUtils.h" // for |nsresult|, |NS_ADDREF|, |NS_GET_TEMPLATE_IID| et al
32
33/*
34 * WARNING: This file defines several macros for internal use only. These
35 * macros begin with the prefix |NSCAP_|. Do not use these macros in your own
36 * code. They are for internal use only for cross-platform compatibility, and
37 * are subject to change without notice.
38 */
39
40#ifdef _MSC_VER
41// Under VC++, we win by inlining StartAssignment.
42# define NSCAP_FEATURE_INLINE_STARTASSIGNMENT
43
44// Also under VC++, at the highest warning level, we are overwhelmed with
45// warnings about (unused) inline functions being removed. This is to be
46// expected with templates, so we disable the warning.
47# pragma warning(disable : 4514)
48#endif
49
50#ifdef DEBUG1
51# define NSCAP_FEATURE_TEST_DONTQUERY_CASES
52#endif
53
54#ifdef __GNUC__4
55// Our use of nsCOMPtr_base::mRawPtr violates the C++ standard's aliasing
56// rules. Mark it with the may_alias attribute so that gcc 3.3 and higher
57// don't reorder instructions based on aliasing assumptions for
58// this variable. Fortunately, gcc versions < 3.3 do not do any
59// optimizations that break nsCOMPtr.
60
61# define NS_MAY_ALIAS_PTR(t)t* __attribute__((__may_alias__)) t* __attribute__((__may_alias__))
62#else
63# define NS_MAY_ALIAS_PTR(t)t* __attribute__((__may_alias__)) t*
64#endif
65
66/*
67 * The following three macros (NSCAP_ADDREF, NSCAP_RELEASE, and
68 * NSCAP_LOG_ASSIGNMENT) allow external clients the ability to add logging or
69 * other interesting debug facilities. In fact, if you want |nsCOMPtr| to
70 * participate in the standard logging facility, you provide
71 * (e.g., in "nsISupportsImpl.h") suitable definitions
72 *
73 * #define NSCAP_ADDREF(this, ptr) NS_ADDREF(ptr)
74 * #define NSCAP_RELEASE(this, ptr) NS_RELEASE(ptr)
75 */
76
77#ifndef NSCAP_ADDREF
78# define NSCAP_ADDREF(this, ptr)mozilla::RefPtrTraits< typename std::remove_reference<decltype
(*ptr)>::type>::AddRef(ptr)
\
79 mozilla::RefPtrTraits< \
80 typename std::remove_reference<decltype(*ptr)>::type>::AddRef(ptr)
81#endif
82
83#ifndef NSCAP_RELEASE
84# define NSCAP_RELEASE(this, ptr)mozilla::RefPtrTraits< typename std::remove_reference<decltype
(*ptr)>::type>::Release(ptr)
\
85 mozilla::RefPtrTraits< \
86 typename std::remove_reference<decltype(*ptr)>::type>::Release(ptr)
87#endif
88
89// Clients can define |NSCAP_LOG_ASSIGNMENT| to perform logging.
90#ifdef NSCAP_LOG_ASSIGNMENT
91// Remember that |NSCAP_LOG_ASSIGNMENT| was defined by some client so that we
92// know to instantiate |~nsGetterAddRefs| in turn to note the external
93// assignment into the |nsCOMPtr|.
94# define NSCAP_LOG_EXTERNAL_ASSIGNMENT
95#else
96// ...otherwise, just strip it out of the code
97# define NSCAP_LOG_ASSIGNMENT(this, ptr)if (ptr != nullptr) NS_LogCOMPtrAddRef((this), ToSupports(ptr
))
98#endif
99
100#ifndef NSCAP_LOG_RELEASE
101# define NSCAP_LOG_RELEASE(this, ptr)if (ptr) NS_LogCOMPtrRelease((this), ToSupports(ptr))
102#endif
103
104namespace mozilla {
105template <class T>
106class OwningNonNull;
107} // namespace mozilla
108
109template <class T>
110inline already_AddRefed<T> dont_AddRef(T* aRawPtr) {
111 return already_AddRefed<T>(aRawPtr);
112}
113
114template <class T>
115inline already_AddRefed<T>&& dont_AddRef(
116 already_AddRefed<T>&& aAlreadyAddRefedPtr) {
117 return std::move(aAlreadyAddRefedPtr);
118}
119
120/*
121 * An nsCOMPtr_helper transforms commonly called getters into typesafe forms
122 * that are more convenient to call, and more efficient to use with |nsCOMPtr|s.
123 * Good candidates for helpers are |QueryInterface()|, |CreateInstance()|, etc.
124 *
125 * Here are the rules for a helper:
126 * - it implements |operator()| to produce an interface pointer
127 * - (except for its name) |operator()| is a valid [XP]COM `getter'
128 * - the interface pointer that it returns is already |AddRef()|ed (as from
129 * any good getter)
130 * - it matches the type requested with the supplied |nsIID| argument
131 * - its constructor provides an optional |nsresult*| that |operator()| can
132 * fill in with an error when it is executed
133 *
134 * See |class nsGetInterface| for an example.
135 */
136class MOZ_STACK_CLASS nsCOMPtr_helper {
137 public:
138 virtual nsresult NS_FASTCALL operator()(const nsIID&, void**) const = 0;
139};
140
141/*
142 * nsQueryInterface could have been implemented as an nsCOMPtr_helper to avoid
143 * adding specialized machinery in nsCOMPtr, but do_QueryInterface is called
144 * often enough that the codesize savings are big enough to warrant the
145 * specialcasing.
146 */
147class MOZ_STACK_CLASS nsQueryInterfaceISupports {
148 public:
149 explicit nsQueryInterfaceISupports(nsISupports* aRawPtr) : mRawPtr(aRawPtr) {}
150
151 nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const;
152
153 private:
154 nsISupports* MOZ_OWNING_REF mRawPtr;
155};
156
157template <typename T>
158class MOZ_STACK_CLASS nsQueryInterface final
159 : public nsQueryInterfaceISupports {
160 public:
161 explicit nsQueryInterface(T* aRawPtr)
162 : nsQueryInterfaceISupports(ToSupports(aRawPtr)) {}
163
164 nsresult NS_FASTCALL operator()(const nsIID& aIID, void** aAnswer) const {
165 return nsQueryInterfaceISupports::operator()(aIID, aAnswer);
166 }
167};
168
169class MOZ_STACK_CLASS nsQueryInterfaceISupportsWithError {
170 public:
171 nsQueryInterfaceISupportsWithError(nsISupports* aRawPtr, nsresult* aError)
172 : mRawPtr(aRawPtr), mErrorPtr(aError) {}
173
174 nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const;
175
176 private:
177 nsISupports* MOZ_OWNING_REF mRawPtr;
178 nsresult* mErrorPtr;
179};
180
181template <typename T>
182class MOZ_STACK_CLASS nsQueryInterfaceWithError final
183 : public nsQueryInterfaceISupportsWithError {
184 public:
185 explicit nsQueryInterfaceWithError(T* aRawPtr, nsresult* aError)
186 : nsQueryInterfaceISupportsWithError(ToSupports(aRawPtr), aError) {}
187
188 nsresult NS_FASTCALL operator()(const nsIID& aIID, void** aAnswer) const {
189 return nsQueryInterfaceISupportsWithError::operator()(aIID, aAnswer);
190 }
191};
192
193namespace mozilla {
194// PointedToType<> is needed so that do_QueryInterface() will work with a
195// variety of smart pointer types in addition to raw pointers. These types
196// include RefPtr<>, nsCOMPtr<>, and OwningNonNull<>.
197template <class T>
198using PointedToType = std::remove_pointer_t<decltype(&*std::declval<T>())>;
199} // namespace mozilla
200
201template <class T>
202inline nsQueryInterface<mozilla::PointedToType<T>> do_QueryInterface(T aPtr) {
203 return nsQueryInterface<mozilla::PointedToType<T>>(aPtr);
204}
205
206template <class T>
207inline nsQueryInterfaceWithError<mozilla::PointedToType<T>> do_QueryInterface(
208 T aRawPtr, nsresult* aError) {
209 return nsQueryInterfaceWithError<mozilla::PointedToType<T>>(aRawPtr, aError);
210}
211
212template <class T>
213inline void do_QueryInterface(already_AddRefed<T>&) {
214 // This signature exists solely to _stop_ you from doing the bad thing.
215 // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by
216 // someone else is an automatic leak. See bug 8221.
217}
218
219template <class T>
220inline void do_QueryInterface(already_AddRefed<T>&, nsresult*) {
221 // This signature exists solely to _stop_ you from doing the bad thing.
222 // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by
223 // someone else is an automatic leak. See bug 8221.
224}
225
226////////////////////////////////////////////////////////////////////////////
227// Using servicemanager with COMPtrs
228class nsGetServiceByCID final {
229 public:
230 explicit nsGetServiceByCID(const nsCID& aCID) : mCID(aCID) {}
231
232 nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
233
234 private:
235 const nsCID& mCID;
236};
237
238class nsGetServiceByCIDWithError final {
239 public:
240 nsGetServiceByCIDWithError(const nsCID& aCID, nsresult* aErrorPtr)
241 : mCID(aCID), mErrorPtr(aErrorPtr) {}
242
243 nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
244
245 private:
246 const nsCID& mCID;
247 nsresult* mErrorPtr;
248};
249
250class nsGetServiceByContractID final {
251 public:
252 explicit nsGetServiceByContractID(const char* aContractID)
253 : mContractID(aContractID) {}
254
255 nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
256
257 private:
258 const char* mContractID;
259};
260
261class nsGetServiceByContractIDWithError final {
262 public:
263 nsGetServiceByContractIDWithError(const char* aContractID,
264 nsresult* aErrorPtr)
265 : mContractID(aContractID), mErrorPtr(aErrorPtr) {}
266
267 nsresult NS_FASTCALL operator()(const nsIID&, void**) const;
268
269 private:
270 const char* mContractID;
271 nsresult* mErrorPtr;
272};
273
274class nsIWeakReference;
275
276// Weak references
277class MOZ_STACK_CLASS nsQueryReferent final {
278 public:
279 nsQueryReferent(nsIWeakReference* aWeakPtr, nsresult* aError)
280 : mWeakPtr(aWeakPtr), mErrorPtr(aError) {}
281
282 nsresult NS_FASTCALL operator()(const nsIID& aIID, void**) const;
283
284 private:
285 nsIWeakReference* MOZ_NON_OWNING_REF mWeakPtr;
286 nsresult* mErrorPtr;
287};
288
289// template<class T> class nsGetterAddRefs;
290
291// Helper for assert_validity method
292template <class T>
293char (&TestForIID(decltype(&NS_GET_TEMPLATE_IID(T)(T::template COMTypeInfo<T, void>::kIID))))[2];
294template <class T>
295char TestForIID(...);
296
297template <class T>
298class MOZ_IS_REFPTR nsCOMPtr final {
299 private:
300 void assign_with_AddRef(T*);
301 template <typename U>
302 void assign_from_qi(const nsQueryInterface<U>, const nsIID&);
303 template <typename U>
304 void assign_from_qi_with_error(const nsQueryInterfaceWithError<U>&,
305 const nsIID&);
306 void assign_from_gs_cid(const nsGetServiceByCID, const nsIID&);
307 void assign_from_gs_cid_with_error(const nsGetServiceByCIDWithError&,
308 const nsIID&);
309 void assign_from_gs_contractid(const nsGetServiceByContractID, const nsIID&);
310 void assign_from_gs_contractid_with_error(
311 const nsGetServiceByContractIDWithError&, const nsIID&);
312 void assign_from_query_referent(const nsQueryReferent&, const nsIID&);
313 void assign_from_helper(const nsCOMPtr_helper&, const nsIID&);
314 void** begin_assignment();
315
316 void assign_assuming_AddRef(T* aNewPtr) {
317 T* oldPtr = mRawPtr;
318 mRawPtr = aNewPtr;
319 NSCAP_LOG_ASSIGNMENT(this, aNewPtr)if (aNewPtr != nullptr) NS_LogCOMPtrAddRef((this), ToSupports
(aNewPtr))
;
320 NSCAP_LOG_RELEASE(this, oldPtr)if (oldPtr) NS_LogCOMPtrRelease((this), ToSupports(oldPtr));
321 if (oldPtr) {
322 NSCAP_RELEASE(this, oldPtr)mozilla::RefPtrTraits< typename std::remove_reference<decltype
(*oldPtr)>::type>::Release(oldPtr)
;
323 }
324 }
325
326 private:
327 T* MOZ_OWNING_REF mRawPtr;
328
329 void assert_validity() {
330 static_assert(1 < sizeof(TestForIID<T>(nullptr)),
331 "nsCOMPtr only works "
332 "for types with IIDs. Either use RefPtr; add an IID to "
333 "your type with NS_DECLARE_STATIC_IID_ACCESSOR/"
334 "NS_DEFINE_STATIC_IID_ACCESSOR; or make the nsCOMPtr point "
335 "to a base class with an IID.");
336 }
337
338 public:
339 typedef T element_type;
340
341 ~nsCOMPtr() {
342 NSCAP_LOG_RELEASE(this, mRawPtr)if (mRawPtr) NS_LogCOMPtrRelease((this), ToSupports(mRawPtr));
48
Branch condition evaluates to a garbage value
343 if (mRawPtr) {
344 NSCAP_RELEASE(this, mRawPtr)mozilla::RefPtrTraits< typename std::remove_reference<decltype
(*mRawPtr)>::type>::Release(mRawPtr)
;
345 }
346 }
347
348#ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES
349 void Assert_NoQueryNeeded() {
350 if (!mRawPtr) {
351 return;
352 }
353 if constexpr (std::is_same_v<T, nsISupports>) {
354 // FIXME: nsCOMPtr<nsISupports> never asserted this, and it currently
355 // fails...
356 return;
357 }
358 // This can't be defined in terms of do_QueryInterface because
359 // that bans casts from a class to itself.
360 void* out = nullptr;
361 mRawPtr->QueryInterface(NS_GET_TEMPLATE_IID(T)(T::template COMTypeInfo<T, void>::kIID), &out);
362 T* query_result = static_cast<T*>(out);
363 MOZ_ASSERT(query_result == mRawPtr, "QueryInterface needed")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(query_result == mRawPtr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(query_result == mRawPtr))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("query_result == mRawPtr"
" (" "QueryInterface needed" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsCOMPtr.h"
, 363); AnnotateMozCrashReason("MOZ_ASSERT" "(" "query_result == mRawPtr"
") (" "QueryInterface needed" ")"); do { *((volatile int*)__null
) = 363; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
364 NS_RELEASE(query_result)do { (query_result)->Release(); (query_result) = 0; } while
(0)
;
365 }
366
367# define NSCAP_ASSERT_NO_QUERY_NEEDED()Assert_NoQueryNeeded(); Assert_NoQueryNeeded();
368#else
369# define NSCAP_ASSERT_NO_QUERY_NEEDED()Assert_NoQueryNeeded();
370#endif
371
372 // Constructors
373
374 nsCOMPtr() : mRawPtr(nullptr) {
375 assert_validity();
376 NSCAP_LOG_ASSIGNMENT(this, nullptr)if (nullptr != nullptr) NS_LogCOMPtrAddRef((this), ToSupports
(nullptr))
;
377 }
378
379 MOZ_IMPLICIT nsCOMPtr(decltype(nullptr)) : mRawPtr(nullptr) {
380 assert_validity();
381 NSCAP_LOG_ASSIGNMENT(this, nullptr)if (nullptr != nullptr) NS_LogCOMPtrAddRef((this), ToSupports
(nullptr))
;
382 }
383
384 nsCOMPtr(const nsCOMPtr<T>& aSmartPtr) : mRawPtr(aSmartPtr.mRawPtr) {
385 assert_validity();
386 if (mRawPtr) {
387 NSCAP_ADDREF(this, mRawPtr)mozilla::RefPtrTraits< typename std::remove_reference<decltype
(*mRawPtr)>::type>::AddRef(mRawPtr)
;
388 }
389 NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.mRawPtr)if (aSmartPtr.mRawPtr != nullptr) NS_LogCOMPtrAddRef((this), ToSupports
(aSmartPtr.mRawPtr))
;
390 }
391
392 template <class U>
393 MOZ_IMPLICIT nsCOMPtr(const nsCOMPtr<U>& aSmartPtr)
394 : mRawPtr(aSmartPtr.get()) {
395 // Make sure that U actually inherits from T
396 static_assert(std::is_base_of<T, U>::value, "U should be a subclass of T");
397 assert_validity();
398 if (mRawPtr) {
399 NSCAP_ADDREF(this, mRawPtr)mozilla::RefPtrTraits< typename std::remove_reference<decltype
(*mRawPtr)>::type>::AddRef(mRawPtr)
;
400 }
401 NSCAP_LOG_ASSIGNMENT(this, aSmartPtr.get())if (aSmartPtr.get() != nullptr) NS_LogCOMPtrAddRef((this), ToSupports
(aSmartPtr.get()))
;
402 }
403
404 nsCOMPtr(nsCOMPtr<T>&& aSmartPtr) : mRawPtr(aSmartPtr.mRawPtr) {
405 assert_validity();
406 aSmartPtr.mRawPtr = nullptr;
407 NSCAP_LOG_ASSIGNMENT(this, mRawPtr)if (mRawPtr != nullptr) NS_LogCOMPtrAddRef((this), ToSupports
(mRawPtr))
;
408 }
409
410 template <class U>
411 MOZ_IMPLICIT nsCOMPtr(nsCOMPtr<U>&& aSmartPtr)
412 : mRawPtr(aSmartPtr.forget().template downcast<T>().take()) {
413 // Make sure that U actually inherits from T
414 static_assert(std::is_base_of<T, U>::value, "U should be a subclass of T");
415 assert_validity();
416 NSCAP_LOG_ASSIGNMENT(this, mRawPtr)if (mRawPtr != nullptr) NS_LogCOMPtrAddRef((this), ToSupports
(mRawPtr))
;
417 NSCAP_ASSERT_NO_QUERY_NEEDED()Assert_NoQueryNeeded();;
418 }
419
420 MOZ_IMPLICIT nsCOMPtr(T* aRawPtr) : mRawPtr(aRawPtr) {
421 assert_validity();
422 if (mRawPtr) {
423 NSCAP_ADDREF(this, mRawPtr)mozilla::RefPtrTraits< typename std::remove_reference<decltype
(*mRawPtr)>::type>::AddRef(mRawPtr)
;
424 }
425 NSCAP_LOG_ASSIGNMENT(this, aRawPtr)if (aRawPtr != nullptr) NS_LogCOMPtrAddRef((this), ToSupports
(aRawPtr))
;
426 NSCAP_ASSERT_NO_QUERY_NEEDED()Assert_NoQueryNeeded();;
427 }
428
429 MOZ_IMPLICIT nsCOMPtr(already_AddRefed<T>& aSmartPtr)
430 : mRawPtr(aSmartPtr.take()) {
431 assert_validity();
432 NSCAP_LOG_ASSIGNMENT(this, mRawPtr)if (mRawPtr != nullptr) NS_LogCOMPtrAddRef((this), ToSupports
(mRawPtr))
;
433 NSCAP_ASSERT_NO_QUERY_NEEDED()Assert_NoQueryNeeded();;
434 }
435
436 // Construct from |otherComPtr.forget()|.
437 MOZ_IMPLICIT nsCOMPtr(already_AddRefed<T>&& aSmartPtr)
438 : mRawPtr(aSmartPtr.take()) {
439 assert_validity();
440 NSCAP_LOG_ASSIGNMENT(this, mRawPtr)if (mRawPtr != nullptr) NS_LogCOMPtrAddRef((this), ToSupports
(mRawPtr))
;
441 NSCAP_ASSERT_NO_QUERY_NEEDED()Assert_NoQueryNeeded();;
442 }
443
444 // Construct from |std::move(otherRefPtr)|.
445 template <typename U>
446 MOZ_IMPLICIT nsCOMPtr(RefPtr<U>&& aSmartPtr)
447 : mRawPtr(static_cast<already_AddRefed<T>>(aSmartPtr.forget()).take()) {
448 assert_validity();
449 // Make sure that U actually inherits from T
450 static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
451 NSCAP_LOG_ASSIGNMENT(this, mRawPtr)if (mRawPtr != nullptr) NS_LogCOMPtrAddRef((this), ToSupports
(mRawPtr))
;
452 NSCAP_ASSERT_NO_QUERY_NEEDED()Assert_NoQueryNeeded();;
453 }
454
455 // Construct from |already_AddRefed|.
456 template <typename U>
457 MOZ_IMPLICIT nsCOMPtr(already_AddRefed<U>& aSmartPtr)
458 : mRawPtr(static_cast<T*>(aSmartPtr.take())) {
459 assert_validity();
460 // But make sure that U actually inherits from T.
461 static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
462 NSCAP_LOG_ASSIGNMENT(this, static_cast<T*>(mRawPtr))if (static_cast<T*>(mRawPtr) != nullptr) NS_LogCOMPtrAddRef
((this), ToSupports(static_cast<T*>(mRawPtr)))
;
463 NSCAP_ASSERT_NO_QUERY_NEEDED()Assert_NoQueryNeeded();;
464 }
465
466 // Construct from |otherComPtr.forget()|.
467 template <typename U>
468 MOZ_IMPLICIT nsCOMPtr(already_AddRefed<U>&& aSmartPtr)
469 : mRawPtr(static_cast<T*>(aSmartPtr.take())) {
470 assert_validity();
471 // But make sure that U actually inherits from T.
472 static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
473 NSCAP_LOG_ASSIGNMENT(this, static_cast<T*>(mRawPtr))if (static_cast<T*>(mRawPtr) != nullptr) NS_LogCOMPtrAddRef
((this), ToSupports(static_cast<T*>(mRawPtr)))
;
474 NSCAP_ASSERT_NO_QUERY_NEEDED()Assert_NoQueryNeeded();;
475 }
476
477 // Construct from |do_QueryInterface(expr)|.
478 template <typename U>
479 MOZ_IMPLICIT nsCOMPtr(const nsQueryInterface<U> aQI) : mRawPtr(nullptr) {
480 assert_validity();
481 NSCAP_LOG_ASSIGNMENT(this, nullptr)if (nullptr != nullptr) NS_LogCOMPtrAddRef((this), ToSupports
(nullptr))
;
482 assign_from_qi(aQI, NS_GET_TEMPLATE_IID(T)(T::template COMTypeInfo<T, void>::kIID));
483 }
484
485 // Construct from |do_QueryInterface(expr, &rv)|.
486 template <typename U>
487 MOZ_IMPLICIT nsCOMPtr(const nsQueryInterfaceWithError<U>& aQI)
488 : mRawPtr(nullptr) {
489 assert_validity();
490 NSCAP_LOG_ASSIGNMENT(this, nullptr)if (nullptr != nullptr) NS_LogCOMPtrAddRef((this), ToSupports
(nullptr))
;
491 assign_from_qi_with_error(aQI, NS_GET_TEMPLATE_IID(T)(T::template COMTypeInfo<T, void>::kIID));
492 }
493
494 // Construct from |do_GetService(cid_expr)|.
495 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCID aGS) : mRawPtr(nullptr) {
496 assert_validity();
497 NSCAP_LOG_ASSIGNMENT(this, nullptr)if (nullptr != nullptr) NS_LogCOMPtrAddRef((this), ToSupports
(nullptr))
;
498 assign_from_gs_cid(aGS, NS_GET_TEMPLATE_IID(T)(T::template COMTypeInfo<T, void>::kIID));
499 }
500
501 // Construct from |do_GetService(cid_expr, &rv)|.
502 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByCIDWithError& aGS)
503 : mRawPtr(nullptr) {
504 assert_validity();
505 NSCAP_LOG_ASSIGNMENT(this, nullptr)if (nullptr != nullptr) NS_LogCOMPtrAddRef((this), ToSupports
(nullptr))
;
506 assign_from_gs_cid_with_error(aGS, NS_GET_TEMPLATE_IID(T)(T::template COMTypeInfo<T, void>::kIID));
507 }
508
509 // Construct from |do_GetService(contractid_expr)|.
510 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractID aGS) : mRawPtr(nullptr) {
511 assert_validity();
512 NSCAP_LOG_ASSIGNMENT(this, nullptr)if (nullptr != nullptr) NS_LogCOMPtrAddRef((this), ToSupports
(nullptr))
;
513 assign_from_gs_contractid(aGS, NS_GET_TEMPLATE_IID(T)(T::template COMTypeInfo<T, void>::kIID));
514 }
515
516 // Construct from |do_GetService(contractid_expr, &rv)|.
517 MOZ_IMPLICIT nsCOMPtr(const nsGetServiceByContractIDWithError& aGS)
518 : mRawPtr(nullptr) {
519 assert_validity();
520 NSCAP_LOG_ASSIGNMENT(this, nullptr)if (nullptr != nullptr) NS_LogCOMPtrAddRef((this), ToSupports
(nullptr))
;
521 assign_from_gs_contractid_with_error(aGS, NS_GET_TEMPLATE_IID(T)(T::template COMTypeInfo<T, void>::kIID));
522 }
523
524 // Construct from |do_QueryReferent(ptr)|
525 MOZ_IMPLICIT nsCOMPtr(const nsQueryReferent& aQueryReferent)
526 : mRawPtr(nullptr) {
527 assert_validity();
528 NSCAP_LOG_ASSIGNMENT(this, nullptr)if (nullptr != nullptr) NS_LogCOMPtrAddRef((this), ToSupports
(nullptr))
;
529 assign_from_query_referent(aQueryReferent, NS_GET_TEMPLATE_IID(T)(T::template COMTypeInfo<T, void>::kIID));
530 }
531
532 // And finally, anything else we might need to construct from can exploit the
533 // nsCOMPtr_helper facility.
534 MOZ_IMPLICIT nsCOMPtr(const nsCOMPtr_helper& aHelper) : mRawPtr(nullptr) {
535 assert_validity();
536 NSCAP_LOG_ASSIGNMENT(this, nullptr)if (nullptr != nullptr) NS_LogCOMPtrAddRef((this), ToSupports
(nullptr))
;
537 assign_from_helper(aHelper, NS_GET_TEMPLATE_IID(T)(T::template COMTypeInfo<T, void>::kIID));
538 NSCAP_ASSERT_NO_QUERY_NEEDED()Assert_NoQueryNeeded();;
539 }
540
541 // construct from |mozilla::NotNull|.
542 template <typename I,
543 typename = std::enable_if_t<!std::is_same_v<I, nsCOMPtr<T>> &&
544 std::is_convertible_v<I, nsCOMPtr<T>>>>
545 MOZ_IMPLICIT nsCOMPtr(const mozilla::NotNull<I>& aSmartPtr)
546 : mRawPtr(nsCOMPtr<T>(aSmartPtr.get()).forget().take()) {}
547
548 // construct from |mozilla::MovingNotNull|.
549 template <typename I,
550 typename = std::enable_if_t<!std::is_same_v<I, nsCOMPtr<T>> &&
551 std::is_convertible_v<I, nsCOMPtr<T>>>>
552 MOZ_IMPLICIT nsCOMPtr(mozilla::MovingNotNull<I>&& aSmartPtr)
553 : mRawPtr(
554 nsCOMPtr<T>(std::move(aSmartPtr).unwrapBasePtr()).forget().take()) {
555 }
556
557 // Defined in OwningNonNull.h
558 template <class U>
559 MOZ_IMPLICIT nsCOMPtr(const mozilla::OwningNonNull<U>& aOther);
560
561 // Assignment operators
562
563 nsCOMPtr<T>& operator=(const nsCOMPtr<T>& aRhs) {
564 assign_with_AddRef(aRhs.mRawPtr);
565 return *this;
566 }
567
568 template <class U>
569 nsCOMPtr<T>& operator=(const nsCOMPtr<U>& aRhs) {
570 // Make sure that U actually inherits from T
571 static_assert(std::is_base_of<T, U>::value, "U should be a subclass of T");
572 assign_with_AddRef(aRhs.get());
573 return *this;
574 }
575
576 nsCOMPtr<T>& operator=(nsCOMPtr<T>&& aRhs) {
577 assign_assuming_AddRef(aRhs.forget().take());
578 return *this;
579 }
580
581 template <class U>
582 nsCOMPtr<T>& operator=(nsCOMPtr<U>&& aRhs) {
583 // Make sure that U actually inherits from T
584 static_assert(std::is_base_of<T, U>::value, "U should be a subclass of T");
585 assign_assuming_AddRef(aRhs.forget().template downcast<T>().take());
586 NSCAP_ASSERT_NO_QUERY_NEEDED()Assert_NoQueryNeeded();;
587 return *this;
588 }
589
590 nsCOMPtr<T>& operator=(T* aRhs) {
591 assign_with_AddRef(aRhs);
592 NSCAP_ASSERT_NO_QUERY_NEEDED()Assert_NoQueryNeeded();;
593 return *this;
594 }
595
596 nsCOMPtr<T>& operator=(decltype(nullptr)) {
597 assign_assuming_AddRef(nullptr);
598 return *this;
599 }
600
601 // Assign from |already_AddRefed|.
602 template <typename U>
603 nsCOMPtr<T>& operator=(already_AddRefed<U>& aRhs) {
604 // Make sure that U actually inherits from T
605 static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
606 assign_assuming_AddRef(static_cast<T*>(aRhs.take()));
607 NSCAP_ASSERT_NO_QUERY_NEEDED()Assert_NoQueryNeeded();;
608 return *this;
609 }
610
611 // Assign from |otherComPtr.forget()|.
612 template <typename U>
613 nsCOMPtr<T>& operator=(already_AddRefed<U>&& aRhs) {
614 // Make sure that U actually inherits from T
615 static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
616 assign_assuming_AddRef(static_cast<T*>(aRhs.take()));
617 NSCAP_ASSERT_NO_QUERY_NEEDED()Assert_NoQueryNeeded();;
618 return *this;
619 }
620
621 // Assign from |std::move(otherRefPtr)|.
622 template <typename U>
623 nsCOMPtr<T>& operator=(RefPtr<U>&& aRhs) {
624 // Make sure that U actually inherits from T
625 static_assert(std::is_base_of<T, U>::value, "U is not a subclass of T");
626 assign_assuming_AddRef(static_cast<T*>(aRhs.forget().take()));
627 NSCAP_ASSERT_NO_QUERY_NEEDED()Assert_NoQueryNeeded();;
628 return *this;
629 }
630
631 // Assign from |do_QueryInterface(expr)|.
632 template <typename U>
633 nsCOMPtr<T>& operator=(const nsQueryInterface<U> aRhs) {
634 assign_from_qi(aRhs, NS_GET_TEMPLATE_IID(T)(T::template COMTypeInfo<T, void>::kIID));
635 return *this;
636 }
637
638 // Assign from |do_QueryInterface(expr, &rv)|.
639 template <typename U>
640 nsCOMPtr<T>& operator=(const nsQueryInterfaceWithError<U>& aRhs) {
641 assign_from_qi_with_error(aRhs, NS_GET_TEMPLATE_IID(T)(T::template COMTypeInfo<T, void>::kIID));
642 return *this;
643 }
644
645 // Assign from |do_GetService(cid_expr)|.
646 nsCOMPtr<T>& operator=(const nsGetServiceByCID aRhs) {
647 assign_from_gs_cid(aRhs, NS_GET_TEMPLATE_IID(T)(T::template COMTypeInfo<T, void>::kIID));
648 return *this;
649 }
650
651 // Assign from |do_GetService(cid_expr, &rv)|.
652 nsCOMPtr<T>& operator=(const nsGetServiceByCIDWithError& aRhs) {
653 assign_from_gs_cid_with_error(aRhs, NS_GET_TEMPLATE_IID(T)(T::template COMTypeInfo<T, void>::kIID));
654 return *this;
655 }
656
657 // Assign from |do_GetService(contractid_expr)|.
658 nsCOMPtr<T>& operator=(const nsGetServiceByContractID aRhs) {
659 assign_from_gs_contractid(aRhs, NS_GET_TEMPLATE_IID(T)(T::template COMTypeInfo<T, void>::kIID));
660 return *this;
661 }
662
663 // Assign from |do_GetService(contractid_expr, &rv)|.
664 nsCOMPtr<T>& operator=(const nsGetServiceByContractIDWithError& aRhs) {
665 assign_from_gs_contractid_with_error(aRhs, NS_GET_TEMPLATE_IID(T)(T::template COMTypeInfo<T, void>::kIID));
666 return *this;
667 }
668
669 // Assign from |do_QueryReferent(ptr)|.
670 nsCOMPtr<T>& operator=(const nsQueryReferent& aRhs) {
671 assign_from_query_referent(aRhs, NS_GET_TEMPLATE_IID(T)(T::template COMTypeInfo<T, void>::kIID));
672 return *this;
673 }
674
675 // And finally, anything else we might need to assign from can exploit the
676 // nsCOMPtr_helper facility.
677 nsCOMPtr<T>& operator=(const nsCOMPtr_helper& aRhs) {
678 assign_from_helper(aRhs, NS_GET_TEMPLATE_IID(T)(T::template COMTypeInfo<T, void>::kIID));
679 NSCAP_ASSERT_NO_QUERY_NEEDED()Assert_NoQueryNeeded();;
680 return *this;
681 }
682
683 // Assign from |mozilla::NotNull|.
684 template <typename I,
685 typename = std::enable_if_t<std::is_convertible_v<I, nsCOMPtr<T>>>>
686 nsCOMPtr<T>& operator=(const mozilla::NotNull<I>& aSmartPtr) {
687 assign_assuming_AddRef(nsCOMPtr<T>(aSmartPtr.get()).forget().take());
688 return *this;
689 }
690
691 // Assign from |mozilla::MovingNotNull|.
692 template <typename I,
693 typename = std::enable_if_t<std::is_convertible_v<I, nsCOMPtr<T>>>>
694 nsCOMPtr<T>& operator=(mozilla::MovingNotNull<I>&& aSmartPtr) {
695 assign_assuming_AddRef(
696 nsCOMPtr<T>(std::move(aSmartPtr).unwrapBasePtr()).forget().take());
697 return *this;
698 }
699
700 // Defined in OwningNonNull.h
701 template <class U>
702 nsCOMPtr<T>& operator=(const mozilla::OwningNonNull<U>& aOther);
703
704 // Exchange ownership with |aRhs|; can save a pair of refcount operations.
705 void swap(nsCOMPtr<T>& aRhs) {
706 T* temp = aRhs.mRawPtr;
707 NSCAP_LOG_ASSIGNMENT(&aRhs, mRawPtr)if (mRawPtr != nullptr) NS_LogCOMPtrAddRef((&aRhs), ToSupports
(mRawPtr))
;
708 NSCAP_LOG_ASSIGNMENT(this, temp)if (temp != nullptr) NS_LogCOMPtrAddRef((this), ToSupports(temp
))
;
709 NSCAP_LOG_RELEASE(this, mRawPtr)if (mRawPtr) NS_LogCOMPtrRelease((this), ToSupports(mRawPtr));
710 NSCAP_LOG_RELEASE(&aRhs, temp)if (temp) NS_LogCOMPtrRelease((&aRhs), ToSupports(temp));
711 aRhs.mRawPtr = mRawPtr;
712 mRawPtr = temp;
713 // |aRhs| maintains the same invariants, so we don't need to
714 // |NSCAP_ASSERT_NO_QUERY_NEEDED|
715 }
716
717 // Exchange ownership with |aRhs|; can save a pair of refcount operations.
718 void swap(T*& aRhs) {
719 T* temp = aRhs;
720 NSCAP_LOG_ASSIGNMENT(this, temp)if (temp != nullptr) NS_LogCOMPtrAddRef((this), ToSupports(temp
))
;
721 NSCAP_LOG_RELEASE(this, mRawPtr)if (mRawPtr) NS_LogCOMPtrRelease((this), ToSupports(mRawPtr));
722 aRhs = reinterpret_cast<T*>(mRawPtr);
723 mRawPtr = temp;
724 NSCAP_ASSERT_NO_QUERY_NEEDED()Assert_NoQueryNeeded();;
725 }
726
727 // Other pointer operators
728
729 // Return the value of mRawPtr and null out mRawPtr. Useful for
730 // already_AddRefed return values.
731 already_AddRefed<T> MOZ_MAY_CALL_AFTER_MUST_RETURN forget() {
732 T* temp = nullptr;
733 swap(temp);
734 return already_AddRefed<T>(temp);
735 }
736
737 // Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
738 // Useful to avoid unnecessary AddRef/Release pairs with "out" parameters
739 // where aRhs bay be a T** or an I** where I is a base class of T.
740 template <typename I>
741 void forget(I** aRhs) {
742 NS_ASSERTION(aRhs, "Null pointer passed to forget!")do { if (!(aRhs)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Null pointer passed to forget!"
, "aRhs", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsCOMPtr.h"
, 742); MOZ_PretendNoReturn(); } } while (0)
;
743 NSCAP_LOG_RELEASE(this, mRawPtr)if (mRawPtr) NS_LogCOMPtrRelease((this), ToSupports(mRawPtr));
744 *aRhs = get();
745 mRawPtr = nullptr;
746 }
747
748 // Prefer the implicit conversion provided automatically by
749 // |operator T*() const|. Use |get()| to resolve ambiguity or to get a
750 // castable pointer.
751 T* get() const { return reinterpret_cast<T*>(mRawPtr); }
752
753 // Makes an nsCOMPtr act like its underlying raw pointer type whenever it is
754 // used in a context where a raw pointer is expected. It is this operator
755 // that makes an nsCOMPtr substitutable for a raw pointer.
756 //
757 // Prefer the implicit use of this operator to calling |get()|, except where
758 // necessary to resolve ambiguity.
759 operator T*() const& { return get(); }
760
761 // Don't allow implicit conversion of temporary nsCOMPtr to raw pointer,
762 // because the refcount might be one and the pointer will immediately become
763 // invalid.
764 operator T*() const&& = delete;
765
766 // Needed to avoid the deleted operator above
767 explicit operator bool() const { return !!mRawPtr; }
768
769 T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN {
770 MOZ_ASSERT(mRawPtr != nullptr,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRawPtr != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mRawPtr != nullptr))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mRawPtr != nullptr"
" (" "You can't dereference a NULL nsCOMPtr with operator->()."
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsCOMPtr.h"
, 771); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRawPtr != nullptr"
") (" "You can't dereference a NULL nsCOMPtr with operator->()."
")"); do { *((volatile int*)__null) = 771; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
771 "You can't dereference a NULL nsCOMPtr with operator->().")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRawPtr != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mRawPtr != nullptr))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mRawPtr != nullptr"
" (" "You can't dereference a NULL nsCOMPtr with operator->()."
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsCOMPtr.h"
, 771); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRawPtr != nullptr"
") (" "You can't dereference a NULL nsCOMPtr with operator->()."
")"); do { *((volatile int*)__null) = 771; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
772 return get();
773 }
774
775 // These are not intended to be used by clients. See |address_of| below.
776 nsCOMPtr<T>* get_address() { return this; }
777 const nsCOMPtr<T>* get_address() const { return this; }
778
779 public:
780 T& operator*() const {
781 MOZ_ASSERT(mRawPtr != nullptr,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRawPtr != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mRawPtr != nullptr))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mRawPtr != nullptr"
" (" "You can't dereference a NULL nsCOMPtr with operator*()."
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsCOMPtr.h"
, 782); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRawPtr != nullptr"
") (" "You can't dereference a NULL nsCOMPtr with operator*()."
")"); do { *((volatile int*)__null) = 782; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
782 "You can't dereference a NULL nsCOMPtr with operator*().")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRawPtr != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mRawPtr != nullptr))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mRawPtr != nullptr"
" (" "You can't dereference a NULL nsCOMPtr with operator*()."
")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nsCOMPtr.h"
, 782); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRawPtr != nullptr"
") (" "You can't dereference a NULL nsCOMPtr with operator*()."
")"); do { *((volatile int*)__null) = 782; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
783 return *get();
784 }
785
786 T** StartAssignment() {
787#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
788 return reinterpret_cast<T**>(begin_assignment());
789#else
790 assign_assuming_AddRef(nullptr);
791 return reinterpret_cast<T**>(&mRawPtr);
792#endif
793 }
794};
795
796template <typename T>
797inline void ImplCycleCollectionUnlink(nsCOMPtr<T>& aField) {
798 aField = nullptr;
799}
800
801template <typename T>
802inline void ImplCycleCollectionTraverse(
803 nsCycleCollectionTraversalCallback& aCallback, nsCOMPtr<T>& aField,
804 const char* aName, uint32_t aFlags = 0) {
805 CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags);
806}
807
808template <class T>
809void nsCOMPtr<T>::assign_with_AddRef(T* aRawPtr) {
810 if (aRawPtr) {
811 NSCAP_ADDREF(this, aRawPtr)mozilla::RefPtrTraits< typename std::remove_reference<decltype
(*aRawPtr)>::type>::AddRef(aRawPtr)
;
812 }
813 assign_assuming_AddRef(aRawPtr);
814}
815
816template <class T>
817template <typename U>
818void nsCOMPtr<T>::assign_from_qi(const nsQueryInterface<U> aQI,
819 const nsIID& aIID) {
820 // Allow QIing to nsISupports from nsISupports as a special-case, since
821 // SameCOMIdentity uses it.
822 static_assert(
823 std::is_same_v<T, nsISupports> ||
824 !(std::is_same_v<T, U> || std::is_base_of<T, U>::value),
825 "don't use do_QueryInterface for compile-time-determinable casts");
826 void* newRawPtr;
827 if (NS_FAILED(aQI(aIID, &newRawPtr))((bool)(__builtin_expect(!!(NS_FAILED_impl(aQI(aIID, &newRawPtr
))), 0)))
) {
828 newRawPtr = nullptr;
829 }
830 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
831}
832
833template <class T>
834template <typename U>
835void nsCOMPtr<T>::assign_from_qi_with_error(
836 const nsQueryInterfaceWithError<U>& aQI, const nsIID& aIID) {
837 static_assert(
838 !(std::is_same_v<T, U> || std::is_base_of<T, U>::value),
839 "don't use do_QueryInterface for compile-time-determinable casts");
840 void* newRawPtr;
841 if (NS_FAILED(aQI(aIID, &newRawPtr))((bool)(__builtin_expect(!!(NS_FAILED_impl(aQI(aIID, &newRawPtr
))), 0)))
) {
842 newRawPtr = nullptr;
843 }
844 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
845}
846
847template <class T>
848void nsCOMPtr<T>::assign_from_gs_cid(const nsGetServiceByCID aGS,
849 const nsIID& aIID) {
850 void* newRawPtr;
851 if (NS_FAILED(aGS(aIID, &newRawPtr))((bool)(__builtin_expect(!!(NS_FAILED_impl(aGS(aIID, &newRawPtr
))), 0)))
) {
852 newRawPtr = nullptr;
853 }
854 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
855}
856
857template <class T>
858void nsCOMPtr<T>::assign_from_gs_cid_with_error(
859 const nsGetServiceByCIDWithError& aGS, const nsIID& aIID) {
860 void* newRawPtr;
861 if (NS_FAILED(aGS(aIID, &newRawPtr))((bool)(__builtin_expect(!!(NS_FAILED_impl(aGS(aIID, &newRawPtr
))), 0)))
) {
862 newRawPtr = nullptr;
863 }
864 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
865}
866
867template <class T>
868void nsCOMPtr<T>::assign_from_gs_contractid(const nsGetServiceByContractID aGS,
869 const nsIID& aIID) {
870 void* newRawPtr;
871 if (NS_FAILED(aGS(aIID, &newRawPtr))((bool)(__builtin_expect(!!(NS_FAILED_impl(aGS(aIID, &newRawPtr
))), 0)))
) {
872 newRawPtr = nullptr;
873 }
874 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
875}
876
877template <class T>
878void nsCOMPtr<T>::assign_from_gs_contractid_with_error(
879 const nsGetServiceByContractIDWithError& aGS, const nsIID& aIID) {
880 void* newRawPtr;
881 if (NS_FAILED(aGS(aIID, &newRawPtr))((bool)(__builtin_expect(!!(NS_FAILED_impl(aGS(aIID, &newRawPtr
))), 0)))
) {
882 newRawPtr = nullptr;
883 }
884 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
885}
886
887template <class T>
888void nsCOMPtr<T>::assign_from_query_referent(
889 const nsQueryReferent& aQueryReferent, const nsIID& aIID) {
890 void* newRawPtr;
891 if (NS_FAILED(aQueryReferent(aIID, &newRawPtr))((bool)(__builtin_expect(!!(NS_FAILED_impl(aQueryReferent(aIID
, &newRawPtr))), 0)))
) {
892 newRawPtr = nullptr;
893 }
894 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
895}
896
897template <class T>
898void nsCOMPtr<T>::assign_from_helper(const nsCOMPtr_helper& helper,
899 const nsIID& aIID) {
900 void* newRawPtr;
901 if (NS_FAILED(helper(aIID, &newRawPtr))((bool)(__builtin_expect(!!(NS_FAILED_impl(helper(aIID, &
newRawPtr))), 0)))
) {
902 newRawPtr = nullptr;
903 }
904 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
905}
906
907template <class T>
908void** nsCOMPtr<T>::begin_assignment() {
909 assign_assuming_AddRef(nullptr);
910 union {
911 T** mT;
912 void** mVoid;
913 } result;
914 result.mT = &mRawPtr;
915 return result.mVoid;
916}
917
918template <class T>
919inline nsCOMPtr<T>* address_of(nsCOMPtr<T>& aPtr) {
920 return aPtr.get_address();
921}
922
923template <class T>
924inline const nsCOMPtr<T>* address_of(const nsCOMPtr<T>& aPtr) {
925 return aPtr.get_address();
926}
927
928/**
929 * This class is designed to be used for anonymous temporary objects in the
930 * argument list of calls that return COM interface pointers, e.g.,
931 *
932 * nsCOMPtr<IFoo> fooP;
933 * ...->QueryInterface(iid, getter_AddRefs(fooP))
934 *
935 * DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
936 *
937 * When initialized with a |nsCOMPtr|, as in the example above, it returns
938 * a |void**|, a |T**|, or an |nsISupports**| as needed, that the outer call
939 * (|QueryInterface| in this case) can fill in.
940 *
941 * This type should be a nested class inside |nsCOMPtr<T>|.
942 */
943template <class T>
944class nsGetterAddRefs {
945 public:
946 explicit nsGetterAddRefs(nsCOMPtr<T>& aSmartPtr)
947 : mTargetSmartPtr(aSmartPtr) {}
948
949#if defined(NSCAP_FEATURE_TEST_DONTQUERY_CASES) || \
950 defined(NSCAP_LOG_EXTERNAL_ASSIGNMENT)
951 ~nsGetterAddRefs() {
952# ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
953 NSCAP_LOG_ASSIGNMENT(reinterpret_cast<void*>(address_of(mTargetSmartPtr)),if (mTargetSmartPtr.get() != nullptr) NS_LogCOMPtrAddRef((reinterpret_cast
<void*>(address_of(mTargetSmartPtr))), ToSupports(mTargetSmartPtr
.get()))
954 mTargetSmartPtr.get())if (mTargetSmartPtr.get() != nullptr) NS_LogCOMPtrAddRef((reinterpret_cast
<void*>(address_of(mTargetSmartPtr))), ToSupports(mTargetSmartPtr
.get()))
;
955# endif
956
957# ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES
958 mTargetSmartPtr.Assert_NoQueryNeeded();
959# endif
960 }
961#endif
962
963 operator void**() {
964 return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
965 }
966
967 operator T**() { return mTargetSmartPtr.StartAssignment(); }
968 T*& operator*() { return *(mTargetSmartPtr.StartAssignment()); }
969
970 private:
971 nsCOMPtr<T>& mTargetSmartPtr;
972};
973
974template <>
975class nsGetterAddRefs<nsISupports> {
976 public:
977 explicit nsGetterAddRefs(nsCOMPtr<nsISupports>& aSmartPtr)
978 : mTargetSmartPtr(aSmartPtr) {}
979
980#ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
981 ~nsGetterAddRefs() {
982 NSCAP_LOG_ASSIGNMENT(reinterpret_cast<void*>(address_of(mTargetSmartPtr)),if (mTargetSmartPtr.get() != nullptr) NS_LogCOMPtrAddRef((reinterpret_cast
<void*>(address_of(mTargetSmartPtr))), ToSupports(mTargetSmartPtr
.get()))
983 mTargetSmartPtr.get())if (mTargetSmartPtr.get() != nullptr) NS_LogCOMPtrAddRef((reinterpret_cast
<void*>(address_of(mTargetSmartPtr))), ToSupports(mTargetSmartPtr
.get()))
;
984 }
985#endif
986
987 operator void**() {
988 return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
989 }
990
991 operator nsISupports**() { return mTargetSmartPtr.StartAssignment(); }
992 nsISupports*& operator*() { return *(mTargetSmartPtr.StartAssignment()); }
993
994 private:
995 nsCOMPtr<nsISupports>& mTargetSmartPtr;
996};
997
998template <class T>
999inline nsGetterAddRefs<T> getter_AddRefs(nsCOMPtr<T>& aSmartPtr) {
1000 return nsGetterAddRefs<T>(aSmartPtr);
1001}
1002
1003template <class T, class DestinationType>
1004inline nsresult CallQueryInterface(
1005 T* aSource, nsGetterAddRefs<DestinationType> aDestination) {
1006 return CallQueryInterface(aSource,
1007 static_cast<DestinationType**>(aDestination));
1008}
1009
1010// Comparing two |nsCOMPtr|s
1011
1012template <class T, class U>
1013inline bool operator==(const nsCOMPtr<T>& aLhs, const nsCOMPtr<U>& aRhs) {
1014 return static_cast<const T*>(aLhs.get()) == static_cast<const U*>(aRhs.get());
1015}
1016
1017template <class T, class U>
1018inline bool operator!=(const nsCOMPtr<T>& aLhs, const nsCOMPtr<U>& aRhs) {
1019 return static_cast<const T*>(aLhs.get()) != static_cast<const U*>(aRhs.get());
1020}
1021
1022// Comparing an |nsCOMPtr| to a raw pointer
1023
1024template <class T, class U>
1025inline bool operator==(const nsCOMPtr<T>& aLhs, const U* aRhs) {
1026 return static_cast<const T*>(aLhs.get()) == aRhs;
1027}
1028
1029template <class T, class U>
1030inline bool operator==(const U* aLhs, const nsCOMPtr<T>& aRhs) {
1031 return aLhs == static_cast<const T*>(aRhs.get());
1032}
1033
1034template <class T, class U>
1035inline bool operator!=(const nsCOMPtr<T>& aLhs, const U* aRhs) {
1036 return static_cast<const T*>(aLhs.get()) != aRhs;
1037}
1038
1039template <class T, class U>
1040inline bool operator!=(const U* aLhs, const nsCOMPtr<T>& aRhs) {
1041 return aLhs != static_cast<const T*>(aRhs.get());
1042}
1043
1044template <class T, class U>
1045inline bool operator==(const nsCOMPtr<T>& aLhs, U* aRhs) {
1046 return static_cast<const T*>(aLhs.get()) == const_cast<const U*>(aRhs);
1047}
1048
1049template <class T, class U>
1050inline bool operator==(U* aLhs, const nsCOMPtr<T>& aRhs) {
1051 return const_cast<const U*>(aLhs) == static_cast<const T*>(aRhs.get());
1052}
1053
1054template <class T, class U>
1055inline bool operator!=(const nsCOMPtr<T>& aLhs, U* aRhs) {
1056 return static_cast<const T*>(aLhs.get()) != const_cast<const U*>(aRhs);
1057}
1058
1059template <class T, class U>
1060inline bool operator!=(U* aLhs, const nsCOMPtr<T>& aRhs) {
1061 return const_cast<const U*>(aLhs) != static_cast<const T*>(aRhs.get());
1062}
1063
1064// Comparing an |nsCOMPtr| to |nullptr|
1065
1066template <class T>
1067inline bool operator==(const nsCOMPtr<T>& aLhs, decltype(nullptr)) {
1068 return aLhs.get() == nullptr;
1069}
1070
1071template <class T>
1072inline bool operator==(decltype(nullptr), const nsCOMPtr<T>& aRhs) {
1073 return nullptr == aRhs.get();
1074}
1075
1076template <class T>
1077inline bool operator!=(const nsCOMPtr<T>& aLhs, decltype(nullptr)) {
1078 return aLhs.get() != nullptr;
1079}
1080
1081template <class T>
1082inline bool operator!=(decltype(nullptr), const nsCOMPtr<T>& aRhs) {
1083 return nullptr != aRhs.get();
1084}
1085
1086// Comparing any two [XP]COM objects for identity
1087
1088inline bool SameCOMIdentity(nsISupports* aLhs, nsISupports* aRhs) {
1089 return nsCOMPtr<nsISupports>(do_QueryInterface(aLhs)) ==
1090 nsCOMPtr<nsISupports>(do_QueryInterface(aRhs));
1091}
1092
1093template <class SourceType, class DestinationType>
1094inline nsresult CallQueryInterface(nsCOMPtr<SourceType>& aSourcePtr,
1095 DestinationType** aDestPtr) {
1096 return CallQueryInterface(aSourcePtr.get(), aDestPtr);
1097}
1098
1099template <class T>
1100RefPtr<T>::RefPtr(const nsQueryReferent& aQueryReferent) {
1101 void* newRawPtr;
1102 if (NS_FAILED(aQueryReferent(NS_GET_TEMPLATE_IID(T), &newRawPtr))((bool)(__builtin_expect(!!(NS_FAILED_impl(aQueryReferent((T::
template COMTypeInfo<T, void>::kIID), &newRawPtr)))
, 0)))
) {
1103 newRawPtr = nullptr;
1104 }
1105 mRawPtr = static_cast<T*>(newRawPtr);
1106}
1107
1108template <class T>
1109RefPtr<T>::RefPtr(const nsCOMPtr_helper& aHelper) {
1110 void* newRawPtr;
1111 if (NS_FAILED(aHelper(NS_GET_TEMPLATE_IID(T), &newRawPtr))((bool)(__builtin_expect(!!(NS_FAILED_impl(aHelper((T::template
COMTypeInfo<T, void>::kIID), &newRawPtr))), 0)))
) {
1112 newRawPtr = nullptr;
1113 }
1114 mRawPtr = static_cast<T*>(newRawPtr);
1115}
1116
1117template <class T>
1118RefPtr<T>& RefPtr<T>::operator=(const nsQueryReferent& aQueryReferent) {
1119 void* newRawPtr;
1120 if (NS_FAILED(aQueryReferent(NS_GET_TEMPLATE_IID(T), &newRawPtr))((bool)(__builtin_expect(!!(NS_FAILED_impl(aQueryReferent((T::
template COMTypeInfo<T, void>::kIID), &newRawPtr)))
, 0)))
) {
1121 newRawPtr = nullptr;
1122 }
1123 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1124 return *this;
1125}
1126
1127template <class T>
1128RefPtr<T>& RefPtr<T>::operator=(const nsCOMPtr_helper& aHelper) {
1129 void* newRawPtr;
1130 if (NS_FAILED(aHelper(NS_GET_TEMPLATE_IID(T), &newRawPtr))((bool)(__builtin_expect(!!(NS_FAILED_impl(aHelper((T::template
COMTypeInfo<T, void>::kIID), &newRawPtr))), 0)))
) {
1131 newRawPtr = nullptr;
1132 }
1133 assign_assuming_AddRef(static_cast<T*>(newRawPtr));
1134 return *this;
1135}
1136
1137template <class T>
1138inline already_AddRefed<T> do_AddRef(const nsCOMPtr<T>& aObj) {
1139 nsCOMPtr<T> ref(aObj);
1140 return ref.forget();
1141}
1142
1143// MOZ_DBG support
1144
1145template <class T>
1146std::ostream& operator<<(std::ostream& aOut, const nsCOMPtr<T>& aObj) {
1147 return mozilla::DebugValue(aOut, aObj.get());
1148}
1149
1150// ToRefPtr allows to move an nsCOMPtr<T> into a RefPtr<T>. Be mindful when
1151// using this, because usually RefPtr<T> should only be used with concrete T and
1152// nsCOMPtr<T> should only be used with XPCOM interface T.
1153template <class T>
1154RefPtr<T> ToRefPtr(nsCOMPtr<T>&& aObj) {
1155 return aObj.forget();
1156}
1157
1158// Integration with ResultExtensions.h
1159template <typename R>
1160auto ResultRefAsParam(nsCOMPtr<R>& aResult) {
1161 return getter_AddRefs(aResult);
1162}
1163
1164namespace mozilla::detail {
1165template <typename T>
1166struct outparam_as_pointer;
1167
1168template <typename T>
1169struct outparam_as_pointer<nsGetterAddRefs<T>> {
1170 using type = T**;
1171};
1172} // namespace mozilla::detail
1173
1174#endif // !defined(nsCOMPtr_h___)