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-20/lib/clang/20 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D _GLIBCXX_ASSERTIONS -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /var/lib/jenkins/workspace/firefox-scan-build/dom/events -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/events -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /var/lib/jenkins/workspace/firefox-scan-build/ipc/chromium/src -I /var/lib/jenkins/workspace/firefox-scan-build/docshell/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/html -I /var/lib/jenkins/workspace/firefox-scan-build/dom/storage -I /var/lib/jenkins/workspace/firefox-scan-build/dom/xml -I /var/lib/jenkins/workspace/firefox-scan-build/dom/xul -I /var/lib/jenkins/workspace/firefox-scan-build/js/xpconnect/wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/layout/forms -I /var/lib/jenkins/workspace/firefox-scan-build/layout/generic -I /var/lib/jenkins/workspace/firefox-scan-build/layout/xul -I /var/lib/jenkins/workspace/firefox-scan-build/layout/xul/tree -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-20/lib/clang/20/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2025-01-20-090804-167946-1 -x c++ /var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp

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

1/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#include "EventStateManager.h"
8
9#include "mozilla/AsyncEventDispatcher.h"
10#include "mozilla/Attributes.h"
11#include "mozilla/EditorBase.h"
12#include "mozilla/EventDispatcher.h"
13#include "mozilla/EventForwards.h"
14#include "mozilla/Hal.h"
15#include "mozilla/HTMLEditor.h"
16#include "mozilla/IMEStateManager.h"
17#include "mozilla/Likely.h"
18#include "mozilla/FocusModel.h"
19#include "mozilla/MiscEvents.h"
20#include "mozilla/MathAlgorithms.h"
21#include "mozilla/MouseEvents.h"
22#include "mozilla/PointerLockManager.h"
23#include "mozilla/PresShell.h"
24#include "mozilla/ScopeExit.h"
25#include "mozilla/ScrollTypes.h"
26#include "mozilla/TextComposition.h"
27#include "mozilla/TextControlElement.h"
28#include "mozilla/TextEditor.h"
29#include "mozilla/TextEvents.h"
30#include "mozilla/TouchEvents.h"
31#include "mozilla/Telemetry.h"
32#include "mozilla/UniquePtr.h"
33#include "mozilla/dom/BrowserBridgeChild.h"
34#include "mozilla/dom/BrowsingContext.h"
35#include "mozilla/dom/CanonicalBrowsingContext.h"
36#include "mozilla/dom/ContentChild.h"
37#include "mozilla/dom/DOMIntersectionObserver.h"
38#include "mozilla/dom/DragEvent.h"
39#include "mozilla/dom/Event.h"
40#include "mozilla/dom/FrameLoaderBinding.h"
41#include "mozilla/dom/HTMLLabelElement.h"
42#include "mozilla/dom/HTMLInputElement.h"
43#include "mozilla/dom/MouseEventBinding.h"
44#include "mozilla/dom/BrowserChild.h"
45#include "mozilla/dom/PointerEventHandler.h"
46#include "mozilla/dom/UIEvent.h"
47#include "mozilla/dom/UIEventBinding.h"
48#include "mozilla/dom/UserActivation.h"
49#include "mozilla/dom/WheelEventBinding.h"
50#include "mozilla/glean/GleanMetrics.h"
51#include "mozilla/ScrollContainerFrame.h"
52#include "mozilla/StaticPrefs_accessibility.h"
53#include "mozilla/StaticPrefs_browser.h"
54#include "mozilla/StaticPrefs_dom.h"
55#include "mozilla/StaticPrefs_layout.h"
56#include "mozilla/StaticPrefs_mousewheel.h"
57#include "mozilla/StaticPrefs_ui.h"
58#include "mozilla/StaticPrefs_zoom.h"
59
60#include "ContentEventHandler.h"
61#include "IMEContentObserver.h"
62#include "WheelHandlingHelper.h"
63#include "RemoteDragStartData.h"
64
65#include "nsCommandParams.h"
66#include "nsCOMPtr.h"
67#include "nsCopySupport.h"
68#include "nsFocusManager.h"
69#include "nsGenericHTMLElement.h"
70#include "nsIClipboard.h"
71#include "nsIContent.h"
72#include "nsIContentInlines.h"
73#include "mozilla/dom/Document.h"
74#include "nsICookieJarSettings.h"
75#include "nsIFrame.h"
76#include "nsFrameLoaderOwner.h"
77#include "nsIWeakReferenceUtils.h"
78#include "nsIWidget.h"
79#include "nsLiteralString.h"
80#include "nsPresContext.h"
81#include "nsTArray.h"
82#include "nsGkAtoms.h"
83#include "nsIFormControl.h"
84#include "nsComboboxControlFrame.h"
85#include "nsIDOMXULControlElement.h"
86#include "nsNameSpaceManager.h"
87#include "nsIBaseWindow.h"
88#include "nsFrameSelection.h"
89#include "nsPIDOMWindow.h"
90#include "nsPIWindowRoot.h"
91#include "nsIWebNavigation.h"
92#include "nsIDocumentViewer.h"
93#include "nsFrameManager.h"
94#include "nsIBrowserChild.h"
95#include "nsMenuPopupFrame.h"
96
97#include "nsIObserverService.h"
98#include "nsIDocShell.h"
99
100#include "nsSubDocumentFrame.h"
101#include "nsLayoutUtils.h"
102#include "nsIInterfaceRequestorUtils.h"
103#include "nsUnicharUtils.h"
104#include "nsContentUtils.h"
105
106#include "imgIContainer.h"
107#include "nsIProperties.h"
108#include "nsISupportsPrimitives.h"
109
110#include "nsServiceManagerUtils.h"
111#include "nsITimer.h"
112#include "nsFontMetrics.h"
113#include "nsIDragService.h"
114#include "nsIDragSession.h"
115#include "mozilla/dom/DataTransfer.h"
116#include "nsContentAreaDragDrop.h"
117#include "nsTreeBodyFrame.h"
118#include "nsIController.h"
119#include "mozilla/Services.h"
120#include "mozilla/dom/ContentParent.h"
121#include "mozilla/dom/Record.h"
122#include "mozilla/dom/Selection.h"
123
124#include "mozilla/Preferences.h"
125#include "mozilla/LookAndFeel.h"
126#include "mozilla/ProfilerLabels.h"
127#include "Units.h"
128
129#ifdef XP_MACOSX
130# import <ApplicationServices/ApplicationServices.h>
131#endif
132
133namespace mozilla {
134
135using namespace dom;
136
137static const LayoutDeviceIntPoint kInvalidRefPoint =
138 LayoutDeviceIntPoint(-1, -1);
139
140static uint32_t gMouseOrKeyboardEventCounter = 0;
141static nsITimer* gUserInteractionTimer = nullptr;
142static nsITimerCallback* gUserInteractionTimerCallback = nullptr;
143
144static const double kCursorLoadingTimeout = 1000; // ms
145MOZ_RUNINIT static AutoWeakFrame gLastCursorSourceFrame;
146static TimeStamp gLastCursorUpdateTime;
147static TimeStamp gTypingStartTime;
148static TimeStamp gTypingEndTime;
149static int32_t gTypingInteractionKeyPresses = 0;
150MOZ_RUNINIT static dom::InteractionData gTypingInteraction = {};
151
152static inline int32_t RoundDown(double aDouble) {
153 return (aDouble > 0) ? static_cast<int32_t>(floor(aDouble))
154 : static_cast<int32_t>(ceil(aDouble));
155}
156
157static bool IsSelectingLink(nsIFrame* aTargetFrame) {
158 if (!aTargetFrame) {
159 return false;
160 }
161 const nsFrameSelection* frameSel = aTargetFrame->GetConstFrameSelection();
162 if (!frameSel || !frameSel->GetDragState()) {
163 return false;
164 }
165
166 if (!nsContentUtils::GetClosestLinkInFlatTree(aTargetFrame->GetContent())) {
167 return false;
168 }
169 return true;
170}
171
172static UniquePtr<WidgetMouseEvent> CreateMouseOrPointerWidgetEvent(
173 WidgetMouseEvent* aMouseEvent, EventMessage aMessage,
174 EventTarget* aRelatedTarget);
175
176/**
177 * Returns the common ancestor for mouseup purpose, given the
178 * current mouseup target and the previous mousedown target.
179 */
180static nsINode* GetCommonAncestorForMouseUp(
181 nsINode* aCurrentMouseUpTarget, nsINode* aLastMouseDownTarget,
182 Maybe<FormControlType>& aLastMouseDownInputControlType) {
183 if (!aCurrentMouseUpTarget || !aLastMouseDownTarget) {
184 return nullptr;
185 }
186
187 if (aCurrentMouseUpTarget == aLastMouseDownTarget) {
188 return aCurrentMouseUpTarget;
189 }
190
191 // Build the chain of parents
192 AutoTArray<nsINode*, 30> parents1;
193 do {
194 parents1.AppendElement(aCurrentMouseUpTarget);
195 aCurrentMouseUpTarget = aCurrentMouseUpTarget->GetFlattenedTreeParentNode();
196 } while (aCurrentMouseUpTarget);
197
198 AutoTArray<nsINode*, 30> parents2;
199 do {
200 parents2.AppendElement(aLastMouseDownTarget);
201 if (aLastMouseDownTarget == parents1.LastElement()) {
202 break;
203 }
204 aLastMouseDownTarget = aLastMouseDownTarget->GetFlattenedTreeParentNode();
205 } while (aLastMouseDownTarget);
206
207 // Find where the parent chain differs
208 uint32_t pos1 = parents1.Length();
209 uint32_t pos2 = parents2.Length();
210 nsINode* parent = nullptr;
211 for (uint32_t len = std::min(pos1, pos2); len > 0; --len) {
212 nsINode* child1 = parents1.ElementAt(--pos1);
213 nsINode* child2 = parents2.ElementAt(--pos2);
214 if (child1 != child2) {
215 break;
216 }
217
218 // If the input control type is different between mouseup and mousedown,
219 // this is not a valid click.
220 if (HTMLInputElement* input = HTMLInputElement::FromNodeOrNull(child1)) {
221 if (aLastMouseDownInputControlType.isSome() &&
222 aLastMouseDownInputControlType.ref() != input->ControlType()) {
223 break;
224 }
225 }
226 parent = child1;
227 }
228
229 return parent;
230}
231
232LazyLogModule sMouseBoundaryLog("MouseBoundaryEvents");
233LazyLogModule sPointerBoundaryLog("PointerBoundaryEvents");
234
235/******************************************************************/
236/* mozilla::UITimerCallback */
237/******************************************************************/
238
239class UITimerCallback final : public nsITimerCallback, public nsINamed {
240 public:
241 UITimerCallback() : mPreviousCount(0) {}
242 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
243 NS_DECL_NSITIMERCALLBACKvirtual nsresult Notify(nsITimer *timer) override; inline void
_ensure_GetName_exists(void) { static_assert(std::is_convertible
<decltype(this), nsINamed*>::value, "nsITimerCallback implementations must also implement nsINamed"
); }
244 NS_DECL_NSINAMEDvirtual nsresult GetName(nsACString& aName) override;
245 private:
246 ~UITimerCallback() = default;
247 uint32_t mPreviousCount;
248};
249
250NS_IMPL_ISUPPORTS(UITimerCallback, nsITimerCallback, nsINamed)MozExternalRefCountType UITimerCallback::AddRef(void) { static_assert
(!std::is_destructible_v<UITimerCallback>, "Reference-counted class "
"UITimerCallback" " should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
250; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("UITimerCallback" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("UITimerCallback" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"UITimerCallback\" != nullptr" " (" "Must specify a name" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"UITimerCallback\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 250; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("UITimerCallback" " not thread-safe"); nsrefcnt
count = ++mRefCnt; NS_LogAddRef((this), (count), ("UITimerCallback"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
UITimerCallback::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 250
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("UITimerCallback" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("UITimerCallback" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"UITimerCallback\" != nullptr" " (" "Must specify a name" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"UITimerCallback\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 250; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("UITimerCallback" " not thread-safe"); const
char* const nametmp = "UITimerCallback"; nsrefcnt count = --
mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count
== 0) { mRefCnt = 1; delete (this); return 0; } return count
; } nsresult UITimerCallback::QueryInterface(const nsIID&
aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 250); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<UITimerCallback, nsITimerCallback>, int32_t
( reinterpret_cast<char*>(static_cast<nsITimerCallback
*>((UITimerCallback*)0x1000)) - reinterpret_cast<char*>
((UITimerCallback*)0x1000))}, {&mozilla::detail::kImplementedIID
<UITimerCallback, nsINamed>, int32_t( reinterpret_cast<
char*>(static_cast<nsINamed*>((UITimerCallback*)0x1000
)) - reinterpret_cast<char*>((UITimerCallback*)0x1000))
}, {&mozilla::detail::kImplementedIID<UITimerCallback,
nsISupports>, int32_t(reinterpret_cast<char*>(static_cast
<nsISupports*>( static_cast<nsITimerCallback*>((UITimerCallback
*)0x1000))) - reinterpret_cast<char*>((UITimerCallback*
)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table)
> 1, "need at least 1 interface"); rv = NS_TableDrivenQI(
static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
251
252// If aTimer is nullptr, this method always sends "user-interaction-inactive"
253// notification.
254NS_IMETHODIMPnsresult
255UITimerCallback::Notify(nsITimer* aTimer) {
256 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
257 if (!obs) return NS_ERROR_FAILURE;
258 if ((gMouseOrKeyboardEventCounter == mPreviousCount) || !aTimer) {
259 gMouseOrKeyboardEventCounter = 0;
260 obs->NotifyObservers(nullptr, "user-interaction-inactive", nullptr);
261 if (gUserInteractionTimer) {
262 gUserInteractionTimer->Cancel();
263 NS_RELEASE(gUserInteractionTimer)do { (gUserInteractionTimer)->Release(); (gUserInteractionTimer
) = 0; } while (0)
;
264 }
265 } else {
266 obs->NotifyObservers(nullptr, "user-interaction-active", nullptr);
267 EventStateManager::UpdateUserActivityTimer();
268
269 if (XRE_IsParentProcess()) {
270 hal::BatteryInformation batteryInfo;
271 hal::GetCurrentBatteryInformation(&batteryInfo);
272 glean::power_battery::percentage_when_user_active.AccumulateSingleSample(
273 uint64_t(batteryInfo.level() * 100));
274 }
275 }
276 mPreviousCount = gMouseOrKeyboardEventCounter;
277 return NS_OK;
278}
279
280NS_IMETHODIMPnsresult
281UITimerCallback::GetName(nsACString& aName) {
282 aName.AssignLiteral("UITimerCallback_timer");
283 return NS_OK;
284}
285
286/******************************************************************/
287/* mozilla::OverOutElementsWrapper */
288/******************************************************************/
289
290NS_IMPL_CYCLE_COLLECTION(OverOutElementsWrapper, mDeepestEnterEventTarget,OverOutElementsWrapper::cycleCollection OverOutElementsWrapper
::_cycleCollectorGlobal; void OverOutElementsWrapper::cycleCollection
::Unlink(void* p) { OverOutElementsWrapper* tmp = DowncastCCParticipant
<OverOutElementsWrapper>(p); ImplCycleCollectionUnlink(
tmp->mDeepestEnterEventTarget); ImplCycleCollectionUnlink(
tmp->mDispatchingOverEventTarget); ImplCycleCollectionUnlink
(tmp->mDispatchingOutOrDeepestLeaveEventTarget); (void)tmp
; } nsresult OverOutElementsWrapper::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { OverOutElementsWrapper
* tmp = DowncastCCParticipant<OverOutElementsWrapper>(p
); cb.DescribeRefCountedNode(tmp->mRefCnt.get(), "OverOutElementsWrapper"
); ImplCycleCollectionTraverse(cb, tmp->mDeepestEnterEventTarget
, "mDeepestEnterEventTarget", 0); ImplCycleCollectionTraverse
(cb, tmp->mDispatchingOverEventTarget, "mDispatchingOverEventTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDispatchingOutOrDeepestLeaveEventTarget
, "mDispatchingOutOrDeepestLeaveEventTarget", 0); (void)tmp; return
NS_OK; }
291 mDispatchingOverEventTarget,OverOutElementsWrapper::cycleCollection OverOutElementsWrapper
::_cycleCollectorGlobal; void OverOutElementsWrapper::cycleCollection
::Unlink(void* p) { OverOutElementsWrapper* tmp = DowncastCCParticipant
<OverOutElementsWrapper>(p); ImplCycleCollectionUnlink(
tmp->mDeepestEnterEventTarget); ImplCycleCollectionUnlink(
tmp->mDispatchingOverEventTarget); ImplCycleCollectionUnlink
(tmp->mDispatchingOutOrDeepestLeaveEventTarget); (void)tmp
; } nsresult OverOutElementsWrapper::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { OverOutElementsWrapper
* tmp = DowncastCCParticipant<OverOutElementsWrapper>(p
); cb.DescribeRefCountedNode(tmp->mRefCnt.get(), "OverOutElementsWrapper"
); ImplCycleCollectionTraverse(cb, tmp->mDeepestEnterEventTarget
, "mDeepestEnterEventTarget", 0); ImplCycleCollectionTraverse
(cb, tmp->mDispatchingOverEventTarget, "mDispatchingOverEventTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDispatchingOutOrDeepestLeaveEventTarget
, "mDispatchingOutOrDeepestLeaveEventTarget", 0); (void)tmp; return
NS_OK; }
292 mDispatchingOutOrDeepestLeaveEventTarget)OverOutElementsWrapper::cycleCollection OverOutElementsWrapper
::_cycleCollectorGlobal; void OverOutElementsWrapper::cycleCollection
::Unlink(void* p) { OverOutElementsWrapper* tmp = DowncastCCParticipant
<OverOutElementsWrapper>(p); ImplCycleCollectionUnlink(
tmp->mDeepestEnterEventTarget); ImplCycleCollectionUnlink(
tmp->mDispatchingOverEventTarget); ImplCycleCollectionUnlink
(tmp->mDispatchingOutOrDeepestLeaveEventTarget); (void)tmp
; } nsresult OverOutElementsWrapper::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { OverOutElementsWrapper
* tmp = DowncastCCParticipant<OverOutElementsWrapper>(p
); cb.DescribeRefCountedNode(tmp->mRefCnt.get(), "OverOutElementsWrapper"
); ImplCycleCollectionTraverse(cb, tmp->mDeepestEnterEventTarget
, "mDeepestEnterEventTarget", 0); ImplCycleCollectionTraverse
(cb, tmp->mDispatchingOverEventTarget, "mDispatchingOverEventTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDispatchingOutOrDeepestLeaveEventTarget
, "mDispatchingOutOrDeepestLeaveEventTarget", 0); (void)tmp; return
NS_OK; }
293NS_IMPL_CYCLE_COLLECTING_ADDREF(OverOutElementsWrapper)MozExternalRefCountType OverOutElementsWrapper::AddRef(void) {
static_assert(!std::is_destructible_v<OverOutElementsWrapper
>, "Reference-counted class " "OverOutElementsWrapper" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 293); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
293; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); _mOwningThread.AssertOwnership("OverOutElementsWrapper"
" not thread-safe"); nsISupports* base = OverOutElementsWrapper
::cycleCollection::Upcast(this); nsrefcnt count = mRefCnt.incr
(base); NS_LogAddRef((this), (count), ("OverOutElementsWrapper"
), (uint32_t)(sizeof(*this))); return count; }
294NS_IMPL_CYCLE_COLLECTING_RELEASE(OverOutElementsWrapper)MozExternalRefCountType OverOutElementsWrapper::Release(void)
{ do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 294); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 294
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); _mOwningThread.AssertOwnership("OverOutElementsWrapper"
" not thread-safe"); nsISupports* base = OverOutElementsWrapper
::cycleCollection::Upcast(this); nsrefcnt count = mRefCnt.decr
(base); NS_LogRelease((this), (count), ("OverOutElementsWrapper"
)); return count; } void OverOutElementsWrapper::DeleteCycleCollectable
(void) { delete (this); }
295
296NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(OverOutElementsWrapper)nsresult OverOutElementsWrapper::QueryInterface(const nsIID&
aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 296); MOZ_PretendNoReturn(); } } while (0); nsISupports* foundInterface
; if (TopThreeWordsEquals( aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID), (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID)) && (LowWordEquals(aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID)) || LowWordEquals(aIID, (nsCycleCollectionISupports::COMTypeInfo
<nsCycleCollectionISupports, void>::kIID)))) { if (LowWordEquals
(aIID, (nsXPCOMCycleCollectionParticipant::COMTypeInfo<nsXPCOMCycleCollectionParticipant
, void>::kIID))) { *aInstancePtr = OverOutElementsWrapper::
cycleCollection::GetParticipant(); return NS_OK; } if (LowWordEquals
(aIID, (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID))) { *aInstancePtr = OverOutElementsWrapper::
cycleCollection::Upcast(this); return NS_OK; } foundInterface
= nullptr; } else
297 NS_INTERFACE_MAP_ENTRY(nsISupports)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupports>)) foundInterface = static_cast
<nsISupports*>(this); else
298NS_INTERFACE_MAP_ENDfoundInterface = 0; nsresult status; if (!foundInterface) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(!aIID.Equals((nsISupports::COMTypeInfo<nsISupports
, void>::kIID)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aIID.Equals((nsISupports::COMTypeInfo
<nsISupports, void>::kIID))))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 298); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
")"); do { *((volatile int*)__null) = 298; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); status = NS_NOINTERFACE
; } else { (foundInterface)->AddRef(); status = NS_OK; } *
aInstancePtr = foundInterface; return status; }
299
300already_AddRefed<nsIWidget> OverOutElementsWrapper::GetLastOverWidget() const {
301 nsCOMPtr<nsIWidget> widget = do_QueryReferent(mLastOverWidget);
302 return widget.forget();
303}
304
305void OverOutElementsWrapper::ContentRemoved(nsIContent& aContent) {
306 if (!mDeepestEnterEventTarget) {
307 return;
308 }
309
310 if (!nsContentUtils::ContentIsFlattenedTreeDescendantOf(
311 mDeepestEnterEventTarget, &aContent)) {
312 return;
313 }
314
315 LogModule* const logModule = mType == BoundaryEventType::Mouse
316 ? sMouseBoundaryLog
317 : sPointerBoundaryLog;
318
319 if (!StaticPrefs::
320 dom_events_mouse_pointer_boundary_keep_enter_targets_after_over_target_removed()) {
321 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"over\" event target (%p) is removed"
, mDeepestEnterEventTarget.get()); } } while (0)
322 ("The last \"over\" event target (%p) is removed",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"over\" event target (%p) is removed"
, mDeepestEnterEventTarget.get()); } } while (0)
323 mDeepestEnterEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"over\" event target (%p) is removed"
, mDeepestEnterEventTarget.get()); } } while (0)
;
324 StoreOverEventTargetAndDeepestEnterEventTarget(nullptr);
325 return;
326 }
327
328 if (mDispatchingOverEventTarget &&
329 (mDeepestEnterEventTarget == mDispatchingOverEventTarget ||
330 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
331 mDispatchingOverEventTarget, &aContent))) {
332 if (mDispatchingOverEventTarget ==
333 mDispatchingOutOrDeepestLeaveEventTarget) {
334 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
335 ("The dispatching \"%s\" event target (%p) is removed",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
336 LastOverEventTargetIsOutEventTarget() ? "out" : "leave",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
337 mDispatchingOutOrDeepestLeaveEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
;
338 mDispatchingOutOrDeepestLeaveEventTarget = nullptr;
339 }
340 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"over\" event target (%p) is removed"
, mDispatchingOverEventTarget.get()); } } while (0)
341 ("The dispatching \"over\" event target (%p) is removed",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"over\" event target (%p) is removed"
, mDispatchingOverEventTarget.get()); } } while (0)
342 mDispatchingOverEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"over\" event target (%p) is removed"
, mDispatchingOverEventTarget.get()); } } while (0)
;
343 mDispatchingOverEventTarget = nullptr;
344 }
345 if (mDispatchingOutOrDeepestLeaveEventTarget &&
346 (mDeepestEnterEventTarget == mDispatchingOutOrDeepestLeaveEventTarget ||
347 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
348 mDispatchingOutOrDeepestLeaveEventTarget, &aContent))) {
349 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
350 ("The dispatching \"%s\" event target (%p) is removed",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
351 LastOverEventTargetIsOutEventTarget() ? "out" : "leave",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
352 mDispatchingOutOrDeepestLeaveEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The dispatching \"%s\" event target (%p) is removed"
, LastOverEventTargetIsOutEventTarget() ? "out" : "leave", mDispatchingOutOrDeepestLeaveEventTarget
.get()); } } while (0)
;
353 mDispatchingOutOrDeepestLeaveEventTarget = nullptr;
354 }
355 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
356 ("The last \"%s\" event target (%p) is removed and now the last "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
357 "deepest enter target becomes %s(%p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
358 LastOverEventTargetIsOutEventTarget() ? "over" : "enter",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
359 mDeepestEnterEventTarget.get(),do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
360 aContent.GetFlattenedTreeParent()do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
361 ? ToString(*aContent.GetFlattenedTreeParent()).c_str()do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
362 : "nullptr",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
363 aContent.GetFlattenedTreeParent()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The last \"%s\" event target (%p) is removed and now the last "
"deepest enter target becomes %s(%p)", LastOverEventTargetIsOutEventTarget
() ? "over" : "enter", mDeepestEnterEventTarget.get(), aContent
.GetFlattenedTreeParent() ? ToString(*aContent.GetFlattenedTreeParent
()).c_str() : "nullptr", aContent.GetFlattenedTreeParent()); }
} while (0)
;
364 UpdateDeepestEnterEventTarget(aContent.GetFlattenedTreeParent());
365}
366
367void OverOutElementsWrapper::TryToRestorePendingRemovedOverTarget(
368 const WidgetEvent* aEvent) {
369 if (!MaybeHasPendingRemovingOverEventTarget()) {
370 return;
371 }
372
373 LogModule* const logModule = mType == BoundaryEventType::Mouse
374 ? sMouseBoundaryLog
375 : sPointerBoundaryLog;
376
377 // If we receive a mouse event immediately, let's try to restore the last
378 // "over" event target as the following "out" event target. We assume that a
379 // synthesized mousemove or another mouse event is being dispatched at latest
380 // the next animation frame from the removal. However, synthesized mouse move
381 // which is enqueued by ContentRemoved() may not sent to this instance because
382 // the target is considered with the latest layout, so the document of this
383 // instance may be moved somewhere before the next animation frame.
384 // Therefore, we should not restore the last "over" target if we receive an
385 // unexpected event like a keyboard event, a wheel event, etc.
386 if (aEvent->AsMouseEvent()) {
387 // Restore the original "over" event target should be allowed only when it's
388 // reconnected under the last deepest "enter" event target because we need
389 // to dispatch "leave" events later at least on the ancestors which have
390 // never been removed from the tree.
391 // XXX If new ancestor is inserted between mDeepestEnterEventTarget and
392 // mPendingToRemoveLastOverEventTarget, we will dispatch "leave" event even
393 // though we have not dispatched "enter" event on the element. For fixing
394 // this, we need to store the full path of the last "out" event target when
395 // it's removed from the tree. I guess we can be relax for this issue
396 // because this hack is required for web apps which reconnect the target
397 // to the same position immediately.
398 // XXX Should be IsInclusiveFlatTreeDescendantOf()? However, it may
399 // be reconnected into a subtree which is different from where the
400 // last over element was.
401 nsCOMPtr<nsIContent> pendingRemovingOverEventTarget =
402 GetPendingRemovingOverEventTarget();
403 if (pendingRemovingOverEventTarget &&
404 pendingRemovingOverEventTarget->IsInclusiveDescendantOf(
405 mDeepestEnterEventTarget)) {
406 // StoreOverEventTargetAndDeepestEnterEventTarget() always resets
407 // mLastOverWidget. When we restore the pending removing "over" event
408 // target, we need to keep storing the original "over" widget too.
409 nsCOMPtr<nsIWeakReference> widget = std::move(mLastOverWidget);
410 StoreOverEventTargetAndDeepestEnterEventTarget(
411 pendingRemovingOverEventTarget);
412 mLastOverWidget = std::move(widget);
413 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
414 ("The \"over\" event target (%p) is restored",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
415 mDeepestEnterEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
;
416 return;
417 }
418 MOZ_LOG(logModule, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
419 ("Forgetting the last \"over\" event target (%p) because it is not "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
420 "reconnected under the deepest enter event target (%p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
421 mPendingRemovingOverEventTarget.get(),do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
422 mDeepestEnterEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because it is not "
"reconnected under the deepest enter event target (%p)", mPendingRemovingOverEventTarget
.get(), mDeepestEnterEventTarget.get()); } } while (0)
;
423 } else {
424 MOZ_LOG(logModule, LogLevel::Debug,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
425 ("Forgetting the last \"over\" event target (%p) because an "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
426 "unexpected event (%s) is being dispatched, that means that "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
427 "EventStateManager didn't receive a synthesized mousemove which "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
428 "should be dispatched at next animation frame from the removal",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
429 mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage)))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Forgetting the last \"over\" event target (%p) because an "
"unexpected event (%s) is being dispatched, that means that "
"EventStateManager didn't receive a synthesized mousemove which "
"should be dispatched at next animation frame from the removal"
, mPendingRemovingOverEventTarget.get(), ToChar(aEvent->mMessage
)); } } while (0)
;
430 }
431
432 // Now, we should not restore mPendingRemovingOverEventTarget to
433 // mDeepestEnterEventTarget anymore since mPendingRemovingOverEventTarget was
434 // moved outside the subtree of mDeepestEnterEventTarget.
435 mPendingRemovingOverEventTarget = nullptr;
436}
437
438void OverOutElementsWrapper::WillDispatchOverAndEnterEvent(
439 nsIContent* aOverEventTarget) {
440 StoreOverEventTargetAndDeepestEnterEventTarget(aOverEventTarget);
441 // Store the first "over" event target we fire and don't refire "over" event
442 // to that element while the first "over" event is still ongoing.
443 mDispatchingOverEventTarget = aOverEventTarget;
444}
445
446void OverOutElementsWrapper::DidDispatchOverAndEnterEvent(
447 nsIContent* aOriginalOverTargetInComposedDoc,
448 nsIWidget* aOverEventTargetWidget) {
449 mDispatchingOverEventTarget = nullptr;
450 mLastOverWidget = do_GetWeakReference(aOverEventTargetWidget);
451
452 // Pointer Events define that once the `pointerover` event target is removed
453 // from the tree, `pointerout` should not be fired on that and the closest
454 // connected ancestor at the target removal should be kept as the deepest
455 // `pointerleave` target. Therefore, we don't need the special handling for
456 // `pointerout` event target if the last `pointerover` target is temporarily
457 // removed from the tree.
458 if (mType == OverOutElementsWrapper::BoundaryEventType::Pointer) {
459 return;
460 }
461
462 // Assume that the caller checks whether aOriginalOverTarget is in the
463 // original document. If we don't enable the strict mouse/pointer event
464 // boundary event dispatching by the pref (see below),
465 // mDeepestEnterEventTarget is set to nullptr when the last "over" target is
466 // removed. Therefore, we cannot check whether aOriginalOverTarget is in the
467 // original document here.
468 if (!aOriginalOverTargetInComposedDoc) {
469 return;
470 }
471 MOZ_ASSERT_IF(mDeepestEnterEventTarget,do { if (mDeepestEnterEventTarget) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mDeepestEnterEventTarget
->GetComposedDoc() == aOriginalOverTargetInComposedDoc->
GetComposedDoc())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget->
GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
")"); do { *((volatile int*)__null) = 473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
472 mDeepestEnterEventTarget->GetComposedDoc() ==do { if (mDeepestEnterEventTarget) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mDeepestEnterEventTarget
->GetComposedDoc() == aOriginalOverTargetInComposedDoc->
GetComposedDoc())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget->
GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
")"); do { *((volatile int*)__null) = 473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
473 aOriginalOverTargetInComposedDoc->GetComposedDoc())do { if (mDeepestEnterEventTarget) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mDeepestEnterEventTarget
->GetComposedDoc() == aOriginalOverTargetInComposedDoc->
GetComposedDoc())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget->
GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget->GetComposedDoc() == aOriginalOverTargetInComposedDoc->GetComposedDoc()"
")"); do { *((volatile int*)__null) = 473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
474 // If the "mouseover" event target is removed temporarily while we're
475 // dispatching "mouseover" and "mouseenter" events and the target gets back
476 // under the deepest enter event target, we should restore the "mouseover"
477 // target.
478 if ((!StaticPrefs::
479 dom_events_mouse_pointer_boundary_keep_enter_targets_after_over_target_removed() &&
480 !mDeepestEnterEventTarget) ||
481 (!LastOverEventTargetIsOutEventTarget() && mDeepestEnterEventTarget &&
482 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
483 aOriginalOverTargetInComposedDoc, mDeepestEnterEventTarget))) {
484 StoreOverEventTargetAndDeepestEnterEventTarget(
485 aOriginalOverTargetInComposedDoc);
486 LogModule* const logModule = mType == BoundaryEventType::Mouse
487 ? sMouseBoundaryLog
488 : sPointerBoundaryLog;
489 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
490 ("The \"over\" event target (%p) is restored",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
491 mDeepestEnterEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "The \"over\" event target (%p) is restored"
, mDeepestEnterEventTarget.get()); } } while (0)
;
492 }
493}
494
495void OverOutElementsWrapper::StoreOverEventTargetAndDeepestEnterEventTarget(
496 nsIContent* aOverEventTargetAndDeepestEnterEventTarget) {
497 mDeepestEnterEventTarget = aOverEventTargetAndDeepestEnterEventTarget;
498 mPendingRemovingOverEventTarget = nullptr;
499 mDeepestEnterEventTargetIsOverEventTarget = !!mDeepestEnterEventTarget;
500 mLastOverWidget = nullptr; // Set it after dispatching the "over" event.
501}
502
503void OverOutElementsWrapper::UpdateDeepestEnterEventTarget(
504 nsIContent* aDeepestEnterEventTarget) {
505 if (MOZ_UNLIKELY(mDeepestEnterEventTarget == aDeepestEnterEventTarget)(__builtin_expect(!!(mDeepestEnterEventTarget == aDeepestEnterEventTarget
), 0))
) {
506 return;
507 }
508
509 if (!aDeepestEnterEventTarget) {
510 // If the root element is removed, we don't need to dispatch "leave"
511 // events on any elements. Therefore, we can forget everything.
512 StoreOverEventTargetAndDeepestEnterEventTarget(nullptr);
513 return;
514 }
515
516 if (LastOverEventTargetIsOutEventTarget()) {
517 MOZ_ASSERT(mDeepestEnterEventTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDeepestEnterEventTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("mDeepestEnterEventTarget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 517); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget"
")"); do { *((volatile int*)__null) = 517; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
518 if (mType == BoundaryEventType::Pointer) {
519 // The spec of Pointer Events defines that once the `pointerover` event
520 // target is removed from the tree, `pointerout` should not be fired on
521 // that and the closest connected ancestor at the target removal should be
522 // kept as the deepest `pointerleave` target. All browsers considers the
523 // last `pointerover` event target is removed immediately when it occurs.
524 // Therefore, we don't need the special handling which we do for the
525 // `mouseout` event target below for considering whether we'll dispatch
526 // `pointerout` on the last `pointerover` target.
527 mPendingRemovingOverEventTarget = nullptr;
528 } else {
529 // Now, the `mouseout` event target is removed from the DOM at least
530 // temporarily. Let's keep storing it for restoring it if it's
531 // reconnected into mDeepestEnterEventTarget in a tick because the other
532 // browsers do not treat temporary removal of the last `mouseover` target
533 // keeps storing it as the next `mouseout` event target.
534 MOZ_ASSERT(!mPendingRemovingOverEventTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mPendingRemovingOverEventTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mPendingRemovingOverEventTarget
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!mPendingRemovingOverEventTarget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 534); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mPendingRemovingOverEventTarget"
")"); do { *((volatile int*)__null) = 534; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
535 MOZ_ASSERT(mDeepestEnterEventTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDeepestEnterEventTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDeepestEnterEventTarget))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("mDeepestEnterEventTarget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 535); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDeepestEnterEventTarget"
")"); do { *((volatile int*)__null) = 535; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
536 mPendingRemovingOverEventTarget =
537 do_GetWeakReference(mDeepestEnterEventTarget);
538 }
539 } else {
540 MOZ_ASSERT(!mDeepestEnterEventTargetIsOverEventTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDeepestEnterEventTargetIsOverEventTarget)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!mDeepestEnterEventTargetIsOverEventTarget))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!mDeepestEnterEventTargetIsOverEventTarget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 540); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDeepestEnterEventTargetIsOverEventTarget"
")"); do { *((volatile int*)__null) = 540; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
541 // If mDeepestEnterEventTarget is not the last "over" event target, we've
542 // already done the complicated state managing above. Therefore, we only
543 // need to update mDeepestEnterEventTarget in this case.
544 }
545 mDeepestEnterEventTarget = aDeepestEnterEventTarget;
546 mDeepestEnterEventTargetIsOverEventTarget = false;
547 // Do not update mLastOverWidget here because it's required to ignore some
548 // following pointer events which are fired on widget under different top
549 // level widget.
550}
551
552/******************************************************************/
553/* mozilla::EventStateManager */
554/******************************************************************/
555
556static uint32_t sESMInstanceCount = 0;
557
558bool EventStateManager::sNormalLMouseEventInProcess = false;
559int16_t EventStateManager::sCurrentMouseBtn = MouseButton::eNotPressed;
560EventStateManager* EventStateManager::sActiveESM = nullptr;
561EventStateManager* EventStateManager::sCursorSettingManager = nullptr;
562MOZ_RUNINIT AutoWeakFrame EventStateManager::sLastDragOverFrame = nullptr;
563LayoutDeviceIntPoint EventStateManager::sPreLockScreenPoint =
564 LayoutDeviceIntPoint(0, 0);
565LayoutDeviceIntPoint EventStateManager::sLastRefPoint = kInvalidRefPoint;
566CSSIntPoint EventStateManager::sLastScreenPoint = CSSIntPoint(0, 0);
567LayoutDeviceIntPoint EventStateManager::sSynthCenteringPoint = kInvalidRefPoint;
568CSSIntPoint EventStateManager::sLastClientPoint = CSSIntPoint(0, 0);
569MOZ_RUNINIT nsCOMPtr<nsIContent> EventStateManager::sDragOverContent = nullptr;
570
571EventStateManager::WheelPrefs* EventStateManager::WheelPrefs::sInstance =
572 nullptr;
573EventStateManager::DeltaAccumulator*
574 EventStateManager::DeltaAccumulator::sInstance = nullptr;
575
576constexpr const StyleCursorKind kInvalidCursorKind =
577 static_cast<StyleCursorKind>(255);
578
579EventStateManager::EventStateManager()
580 : mLockCursor(kInvalidCursorKind),
581 mCurrentTarget(nullptr),
582 // init d&d gesture state machine variables
583 mGestureDownPoint(0, 0),
584 mGestureModifiers(0),
585 mGestureDownButtons(0),
586 mGestureDownButton(0),
587 mPresContext(nullptr),
588 mShouldAlwaysUseLineDeltas(false),
589 mShouldAlwaysUseLineDeltasInitialized(false),
590 mGestureDownInTextControl(false),
591 mInTouchDrag(false),
592 m_haveShutdown(false) {
593 if (sESMInstanceCount == 0) {
594 gUserInteractionTimerCallback = new UITimerCallback();
595 if (gUserInteractionTimerCallback) NS_ADDREF(gUserInteractionTimerCallback)(gUserInteractionTimerCallback)->AddRef();
596 UpdateUserActivityTimer();
597 }
598 ++sESMInstanceCount;
599}
600
601nsresult EventStateManager::UpdateUserActivityTimer() {
602 if (!gUserInteractionTimerCallback) return NS_OK;
603
604 if (!gUserInteractionTimer) {
605 gUserInteractionTimer = NS_NewTimer().take();
606 }
607
608 if (gUserInteractionTimer) {
609 gUserInteractionTimer->InitWithCallback(
610 gUserInteractionTimerCallback,
611 StaticPrefs::dom_events_user_interaction_interval(),
612 nsITimer::TYPE_ONE_SHOT);
613 }
614 return NS_OK;
615}
616
617nsresult EventStateManager::Init() {
618 nsCOMPtr<nsIObserverService> observerService =
619 mozilla::services::GetObserverService();
620 if (!observerService) return NS_ERROR_FAILURE;
621
622 observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown", true);
623
624 return NS_OK;
625}
626
627bool EventStateManager::ShouldAlwaysUseLineDeltas() {
628 if (MOZ_UNLIKELY(!mShouldAlwaysUseLineDeltasInitialized)(__builtin_expect(!!(!mShouldAlwaysUseLineDeltasInitialized),
0))
) {
629 mShouldAlwaysUseLineDeltasInitialized = true;
630 mShouldAlwaysUseLineDeltas =
631 !StaticPrefs::dom_event_wheel_deltaMode_lines_disabled();
632 if (!mShouldAlwaysUseLineDeltas && mDocument) {
633 if (nsIPrincipal* principal =
634 mDocument->GetPrincipalForPrefBasedHacks()) {
635 mShouldAlwaysUseLineDeltas = principal->IsURIInPrefList(
636 "dom.event.wheel-deltaMode-lines.always-enabled");
637 }
638 }
639 }
640 return mShouldAlwaysUseLineDeltas;
641}
642
643EventStateManager::~EventStateManager() {
644 ReleaseCurrentIMEContentObserver();
645
646 if (sActiveESM == this) {
647 sActiveESM = nullptr;
648 }
649
650 if (StaticPrefs::ui_click_hold_context_menus()) {
651 KillClickHoldTimer();
652 }
653
654 if (sCursorSettingManager == this) {
655 sCursorSettingManager = nullptr;
656 }
657
658 --sESMInstanceCount;
659 if (sESMInstanceCount == 0) {
660 WheelTransaction::Shutdown();
661 if (gUserInteractionTimerCallback) {
662 gUserInteractionTimerCallback->Notify(nullptr);
663 NS_RELEASE(gUserInteractionTimerCallback)do { (gUserInteractionTimerCallback)->Release(); (gUserInteractionTimerCallback
) = 0; } while (0)
;
664 }
665 if (gUserInteractionTimer) {
666 gUserInteractionTimer->Cancel();
667 NS_RELEASE(gUserInteractionTimer)do { (gUserInteractionTimer)->Release(); (gUserInteractionTimer
) = 0; } while (0)
;
668 }
669 WheelPrefs::Shutdown();
670 DeltaAccumulator::Shutdown();
671 }
672
673 if (sDragOverContent && sDragOverContent->OwnerDoc() == mDocument) {
674 sDragOverContent = nullptr;
675 }
676
677 if (!m_haveShutdown) {
678 Shutdown();
679
680 // Don't remove from Observer service in Shutdown because Shutdown also
681 // gets called from xpcom shutdown observer. And we don't want to remove
682 // from the service in that case.
683
684 nsCOMPtr<nsIObserverService> observerService =
685 mozilla::services::GetObserverService();
686 if (observerService) {
687 observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown");
688 }
689 }
690}
691
692nsresult EventStateManager::Shutdown() {
693 m_haveShutdown = true;
694 return NS_OK;
695}
696
697NS_IMETHODIMPnsresult
698EventStateManager::Observe(nsISupports* aSubject, const char* aTopic,
699 const char16_t* someData) {
700 if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown")) {
701 Shutdown();
702 }
703
704 return NS_OK;
705}
706
707NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(EventStateManager)nsresult EventStateManager::QueryInterface(const nsIID& aIID
, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 707); MOZ_PretendNoReturn(); } } while (0); nsISupports* foundInterface
; if (TopThreeWordsEquals( aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID), (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID)) && (LowWordEquals(aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID)) || LowWordEquals(aIID, (nsCycleCollectionISupports::COMTypeInfo
<nsCycleCollectionISupports, void>::kIID)))) { if (LowWordEquals
(aIID, (nsXPCOMCycleCollectionParticipant::COMTypeInfo<nsXPCOMCycleCollectionParticipant
, void>::kIID))) { *aInstancePtr = EventStateManager::cycleCollection
::GetParticipant(); return NS_OK; } if (LowWordEquals(aIID, (
nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID))) { *aInstancePtr = EventStateManager::cycleCollection
::Upcast(this); return NS_OK; } foundInterface = nullptr; } else
708 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupports>)) foundInterface = static_cast
<nsISupports*>(static_cast<nsIObserver*>(this)); else
709 NS_INTERFACE_MAP_ENTRY(nsIObserver)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIObserver>)) foundInterface = static_cast
<nsIObserver*>(this); else
710 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupportsWeakReference>)) foundInterface
= static_cast<nsISupportsWeakReference*>(this); else
711NS_INTERFACE_MAP_ENDfoundInterface = 0; nsresult status; if (!foundInterface) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(!aIID.Equals((nsISupports::COMTypeInfo<nsISupports
, void>::kIID)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aIID.Equals((nsISupports::COMTypeInfo
<nsISupports, void>::kIID))))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 711); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
")"); do { *((volatile int*)__null) = 711; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); status = NS_NOINTERFACE
; } else { (foundInterface)->AddRef(); status = NS_OK; } *
aInstancePtr = foundInterface; return status; }
712
713NS_IMPL_CYCLE_COLLECTING_ADDREF(EventStateManager)MozExternalRefCountType EventStateManager::AddRef(void) { static_assert
(!std::is_destructible_v<EventStateManager>, "Reference-counted class "
"EventStateManager" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 713); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
713; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); _mOwningThread.AssertOwnership("EventStateManager"
" not thread-safe"); nsISupports* base = EventStateManager::
cycleCollection::Upcast(this); nsrefcnt count = mRefCnt.incr(
base); NS_LogAddRef((this), (count), ("EventStateManager"), (
uint32_t)(sizeof(*this))); return count; }
714NS_IMPL_CYCLE_COLLECTING_RELEASE(EventStateManager)MozExternalRefCountType EventStateManager::Release(void) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 714); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 714
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); _mOwningThread.AssertOwnership("EventStateManager" " not thread-safe"
); nsISupports* base = EventStateManager::cycleCollection::Upcast
(this); nsrefcnt count = mRefCnt.decr(base); NS_LogRelease((this
), (count), ("EventStateManager")); return count; } void EventStateManager
::DeleteCycleCollectable(void) { delete (this); }
715
716NS_IMPL_CYCLE_COLLECTION_WEAK(EventStateManager, mCurrentTargetContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
717 mGestureDownContent, mGestureDownFrameOwner,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
718 mLastLeftMouseDownInfo.mLastMouseDownContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
719 mLastMiddleMouseDownInfo.mLastMouseDownContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
720 mLastRightMouseDownInfo.mLastMouseDownContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
721 mActiveContent, mHoverContent, mURLTargetContent,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
722 mPopoverPointerDownTarget, mMouseEnterLeaveHelper,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
723 mPointersEnterLeaveHelper, mDocument,EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
724 mIMEContentObserver, mAccessKeys)EventStateManager::cycleCollection EventStateManager::_cycleCollectorGlobal
; void EventStateManager::cycleCollection::Unlink(void* p) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); ImplCycleCollectionUnlink
(tmp->mCurrentTargetContent); ImplCycleCollectionUnlink(tmp
->mGestureDownContent); ImplCycleCollectionUnlink(tmp->
mGestureDownFrameOwner); ImplCycleCollectionUnlink(tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mLastRightMouseDownInfo
.mLastMouseDownContent); ImplCycleCollectionUnlink(tmp->mActiveContent
); ImplCycleCollectionUnlink(tmp->mHoverContent); ImplCycleCollectionUnlink
(tmp->mURLTargetContent); ImplCycleCollectionUnlink(tmp->
mPopoverPointerDownTarget); ImplCycleCollectionUnlink(tmp->
mMouseEnterLeaveHelper); ImplCycleCollectionUnlink(tmp->mPointersEnterLeaveHelper
); ImplCycleCollectionUnlink(tmp->mDocument); ImplCycleCollectionUnlink
(tmp->mIMEContentObserver); ImplCycleCollectionUnlink(tmp->
mAccessKeys); tmp->ClearWeakReferences(); (void)tmp; } nsresult
EventStateManager::cycleCollection::TraverseNative( void* p,
nsCycleCollectionTraversalCallback& cb) { EventStateManager
* tmp = DowncastCCParticipant<EventStateManager>(p); cb
.DescribeRefCountedNode(tmp->mRefCnt.get(), "EventStateManager"
); ImplCycleCollectionTraverse(cb, tmp->mCurrentTargetContent
, "mCurrentTargetContent", 0); ImplCycleCollectionTraverse(cb
, tmp->mGestureDownContent, "mGestureDownContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mGestureDownFrameOwner, "mGestureDownFrameOwner"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastLeftMouseDownInfo
.mLastMouseDownContent, "mLastLeftMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastMiddleMouseDownInfo
.mLastMouseDownContent, "mLastMiddleMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mLastRightMouseDownInfo
.mLastMouseDownContent, "mLastRightMouseDownInfo.mLastMouseDownContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveContent,
"mActiveContent", 0); ImplCycleCollectionTraverse(cb, tmp->
mHoverContent, "mHoverContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mURLTargetContent, "mURLTargetContent", 0); ImplCycleCollectionTraverse
(cb, tmp->mPopoverPointerDownTarget, "mPopoverPointerDownTarget"
, 0); ImplCycleCollectionTraverse(cb, tmp->mMouseEnterLeaveHelper
, "mMouseEnterLeaveHelper", 0); ImplCycleCollectionTraverse(cb
, tmp->mPointersEnterLeaveHelper, "mPointersEnterLeaveHelper"
, 0); ImplCycleCollectionTraverse(cb, tmp->mDocument, "mDocument"
, 0); ImplCycleCollectionTraverse(cb, tmp->mIMEContentObserver
, "mIMEContentObserver", 0); ImplCycleCollectionTraverse(cb, tmp
->mAccessKeys, "mAccessKeys", 0); (void)tmp; return NS_OK;
}
725
726void EventStateManager::ReleaseCurrentIMEContentObserver() {
727 if (mIMEContentObserver) {
728 mIMEContentObserver->DisconnectFromEventStateManager();
729 }
730 mIMEContentObserver = nullptr;
731}
732
733void EventStateManager::OnStartToObserveContent(
734 IMEContentObserver* aIMEContentObserver) {
735 if (mIMEContentObserver == aIMEContentObserver) {
736 return;
737 }
738 ReleaseCurrentIMEContentObserver();
739 mIMEContentObserver = aIMEContentObserver;
740}
741
742void EventStateManager::OnStopObservingContent(
743 IMEContentObserver* aIMEContentObserver) {
744 aIMEContentObserver->DisconnectFromEventStateManager();
745 NS_ENSURE_TRUE_VOID(mIMEContentObserver == aIMEContentObserver)do { if ((__builtin_expect(!!(!(mIMEContentObserver == aIMEContentObserver
)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mIMEContentObserver == aIMEContentObserver"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 745); return; } } while (false)
;
746 mIMEContentObserver = nullptr;
747}
748
749void EventStateManager::TryToFlushPendingNotificationsToIME() {
750 if (mIMEContentObserver) {
751 mIMEContentObserver->TryToFlushPendingNotifications(true);
752 }
753}
754
755static bool IsMessageMouseUserActivity(EventMessage aMessage) {
756 return aMessage == eMouseMove || aMessage == eMouseUp ||
757 aMessage == eMouseDown || aMessage == ePointerAuxClick ||
758 aMessage == eMouseDoubleClick || aMessage == ePointerClick ||
759 aMessage == eMouseActivate || aMessage == eMouseLongTap;
760}
761
762static bool IsMessageGamepadUserActivity(EventMessage aMessage) {
763 return aMessage == eGamepadButtonDown || aMessage == eGamepadButtonUp ||
764 aMessage == eGamepadAxisMove;
765}
766
767// static
768bool EventStateManager::IsKeyboardEventUserActivity(WidgetEvent* aEvent) {
769 // We ignore things that shouldn't cause popups, but also things that look
770 // like shortcut presses. In some obscure cases these may actually be
771 // website input, but any meaningful website will have other input anyway,
772 // and we can't very well tell whether shortcut input was supposed to be
773 // directed at chrome or the document.
774
775 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
776 // Access keys should be treated as page interaction.
777 if (keyEvent->ModifiersMatchWithAccessKey(AccessKeyType::eContent)) {
778 return true;
779 }
780 if (!keyEvent->CanTreatAsUserInput() || keyEvent->IsControl() ||
781 keyEvent->IsMeta() || keyEvent->IsAlt()) {
782 return false;
783 }
784 // Deal with function keys:
785 switch (keyEvent->mKeyNameIndex) {
786 case KEY_NAME_INDEX_F1:
787 case KEY_NAME_INDEX_F2:
788 case KEY_NAME_INDEX_F3:
789 case KEY_NAME_INDEX_F4:
790 case KEY_NAME_INDEX_F5:
791 case KEY_NAME_INDEX_F6:
792 case KEY_NAME_INDEX_F7:
793 case KEY_NAME_INDEX_F8:
794 case KEY_NAME_INDEX_F9:
795 case KEY_NAME_INDEX_F10:
796 case KEY_NAME_INDEX_F11:
797 case KEY_NAME_INDEX_F12:
798 case KEY_NAME_INDEX_F13:
799 case KEY_NAME_INDEX_F14:
800 case KEY_NAME_INDEX_F15:
801 case KEY_NAME_INDEX_F16:
802 case KEY_NAME_INDEX_F17:
803 case KEY_NAME_INDEX_F18:
804 case KEY_NAME_INDEX_F19:
805 case KEY_NAME_INDEX_F20:
806 case KEY_NAME_INDEX_F21:
807 case KEY_NAME_INDEX_F22:
808 case KEY_NAME_INDEX_F23:
809 case KEY_NAME_INDEX_F24:
810 return false;
811 default:
812 return true;
813 }
814}
815
816static void OnTypingInteractionEnded() {
817 // We don't consider a single keystroke to be typing.
818 if (gTypingInteractionKeyPresses > 1) {
819 gTypingInteraction.mInteractionCount += gTypingInteractionKeyPresses;
820 gTypingInteraction.mInteractionTimeInMilliseconds += static_cast<uint32_t>(
821 std::ceil((gTypingEndTime - gTypingStartTime).ToMilliseconds()));
822 }
823
824 gTypingInteractionKeyPresses = 0;
825 gTypingStartTime = TimeStamp();
826 gTypingEndTime = TimeStamp();
827}
828
829static void HandleKeyUpInteraction(WidgetKeyboardEvent* aKeyEvent) {
830 if (EventStateManager::IsKeyboardEventUserActivity(aKeyEvent)) {
831 TimeStamp now = TimeStamp::Now();
832 if (gTypingEndTime.IsNull()) {
833 gTypingEndTime = now;
834 }
835 TimeDuration delay = now - gTypingEndTime;
836 // Has it been too long since the last keystroke to be considered typing?
837 if (gTypingInteractionKeyPresses > 0 &&
838 delay >
839 TimeDuration::FromMilliseconds(
840 StaticPrefs::browser_places_interactions_typing_timeout_ms())) {
841 OnTypingInteractionEnded();
842 }
843 gTypingInteractionKeyPresses++;
844 if (gTypingStartTime.IsNull()) {
845 gTypingStartTime = now;
846 }
847 gTypingEndTime = now;
848 }
849}
850
851nsresult EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
852 WidgetEvent* aEvent,
853 nsIFrame* aTargetFrame,
854 nsIContent* aTargetContent,
855 nsEventStatus* aStatus,
856 nsIContent* aOverrideClickTarget) {
857 AUTO_PROFILER_LABEL("EventStateManager::PreHandleEvent", DOM)mozilla::AutoProfilerLabel raiiObject857( "EventStateManager::PreHandleEvent"
, nullptr, JS::ProfilingCategoryPair::DOM)
;
858 NS_ENSURE_ARG_POINTER(aStatus)do { if ((__builtin_expect(!!(!(aStatus)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStatus" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 858); return NS_ERROR_INVALID_POINTER; } } while (false)
;
859 NS_ENSURE_ARG(aPresContext)do { if ((__builtin_expect(!!(!(aPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 859); return NS_ERROR_INVALID_ARG; } } while (false)
;
860 if (!aEvent) {
861 NS_ERROR("aEvent is null. This should never happen.")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "aEvent is null. This should never happen."
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 861); MOZ_PretendNoReturn(); } while (0)
;
862 return NS_ERROR_NULL_POINTER;
863 }
864
865 NS_WARNING_ASSERTION(do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
866 !aTargetFrame || !aTargetFrame->GetContent() ||do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
867 aTargetFrame->GetContent() == aTargetContent ||do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
868 aTargetFrame->GetContent()->GetFlattenedTreeParent() ==do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
869 aTargetContent ||do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
870 aTargetFrame->IsGeneratedContentFrame(),do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
871 "aTargetFrame should be related with aTargetContent")do { if (!(!aTargetFrame || !aTargetFrame->GetContent() ||
aTargetFrame->GetContent() == aTargetContent || aTargetFrame
->GetContent()->GetFlattenedTreeParent() == aTargetContent
|| aTargetFrame->IsGeneratedContentFrame())) { NS_DebugBreak
(NS_DEBUG_WARNING, "aTargetFrame should be related with aTargetContent"
, "!aTargetFrame || !aTargetFrame->GetContent() || aTargetFrame->GetContent() == aTargetContent || aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent || aTargetFrame->IsGeneratedContentFrame()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 871); } } while (false)
;
872#if DEBUG1
873 if (aTargetFrame && aTargetFrame->IsGeneratedContentFrame()) {
874 nsCOMPtr<nsIContent> targetContent;
875 aTargetFrame->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
876 MOZ_ASSERT(aTargetContent == targetContent,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTargetContent == targetContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTargetContent == targetContent
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aTargetContent == targetContent" " (" "Unexpected target for generated content frame!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTargetContent == targetContent"
") (" "Unexpected target for generated content frame!" ")");
do { *((volatile int*)__null) = 877; __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
877 "Unexpected target for generated content frame!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTargetContent == targetContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTargetContent == targetContent
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aTargetContent == targetContent" " (" "Unexpected target for generated content frame!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 877); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTargetContent == targetContent"
") (" "Unexpected target for generated content frame!" ")");
do { *((volatile int*)__null) = 877; __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
878 }
879#endif
880
881 mCurrentTarget = aTargetFrame;
882 mCurrentTargetContent = nullptr;
883
884 // Do not take account eMouseEnterIntoWidget/ExitFromWidget so that loading
885 // a page when user is not active doesn't change the state to active.
886 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
887 if (aEvent->IsTrusted() &&
888 ((mouseEvent && mouseEvent->IsReal() &&
889 IsMessageMouseUserActivity(mouseEvent->mMessage)) ||
890 aEvent->mClass == eWheelEventClass ||
891 aEvent->mClass == ePointerEventClass ||
892 aEvent->mClass == eTouchEventClass ||
893 aEvent->mClass == eKeyboardEventClass ||
894 (aEvent->mClass == eDragEventClass && aEvent->mMessage == eDrop) ||
895 IsMessageGamepadUserActivity(aEvent->mMessage))) {
896 if (gMouseOrKeyboardEventCounter == 0) {
897 nsCOMPtr<nsIObserverService> obs =
898 mozilla::services::GetObserverService();
899 if (obs) {
900 obs->NotifyObservers(nullptr, "user-interaction-active", nullptr);
901 UpdateUserActivityTimer();
902 }
903 }
904 ++gMouseOrKeyboardEventCounter;
905
906 nsCOMPtr<nsINode> node = aTargetContent;
907 if (node &&
908 ((aEvent->mMessage == eKeyUp && IsKeyboardEventUserActivity(aEvent)) ||
909 aEvent->mMessage == eMouseUp || aEvent->mMessage == eWheel ||
910 aEvent->mMessage == eTouchEnd || aEvent->mMessage == ePointerUp ||
911 aEvent->mMessage == eDrop)) {
912 Document* doc = node->OwnerDoc();
913 while (doc) {
914 doc->SetUserHasInteracted();
915 doc = nsContentUtils::IsChildOfSameType(doc)
916 ? doc->GetInProcessParentDocument()
917 : nullptr;
918 }
919 }
920 }
921
922 WheelTransaction::OnEvent(aEvent);
923
924 // Focus events don't necessarily need a frame.
925 if (!mCurrentTarget && !aTargetContent) {
926 NS_ERROR("mCurrentTarget and aTargetContent are null")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "mCurrentTarget and aTargetContent are null"
, "Error", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 926); MOZ_PretendNoReturn(); } while (0)
;
927 return NS_ERROR_NULL_POINTER;
928 }
929#ifdef DEBUG1
930 if (aEvent->HasDragEventMessage() && PointerLockManager::IsLocked()) {
931 NS_ASSERTION(PointerLockManager::IsLocked(),do { if (!(PointerLockManager::IsLocked())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Pointer is locked. Drag events should be suppressed when "
"the pointer is locked.", "PointerLockManager::IsLocked()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 933); MOZ_PretendNoReturn(); } } while (0)
932 "Pointer is locked. Drag events should be suppressed when "do { if (!(PointerLockManager::IsLocked())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Pointer is locked. Drag events should be suppressed when "
"the pointer is locked.", "PointerLockManager::IsLocked()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 933); MOZ_PretendNoReturn(); } } while (0)
933 "the pointer is locked.")do { if (!(PointerLockManager::IsLocked())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Pointer is locked. Drag events should be suppressed when "
"the pointer is locked.", "PointerLockManager::IsLocked()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 933); MOZ_PretendNoReturn(); } } while (0)
;
934 }
935#endif
936 // Store last known screenPoint and clientPoint so pointer lock
937 // can use these values as constants.
938 if (aEvent->IsTrusted() &&
939 ((mouseEvent && mouseEvent->IsReal()) ||
940 aEvent->mClass == eWheelEventClass) &&
941 !PointerLockManager::IsLocked()) {
942 // XXX Probably doesn't matter much, but storing these in CSS pixels instead
943 // of device pixels means behavior can be a bit odd if you zoom while
944 // pointer-locked.
945 sLastScreenPoint = RoundedToInt(
946 Event::GetScreenCoords(aPresContext, aEvent, aEvent->mRefPoint)
947 .extract());
948 sLastClientPoint = RoundedToInt(Event::GetClientCoords(
949 aPresContext, aEvent, aEvent->mRefPoint, CSSDoublePoint{0, 0}));
950 }
951
952 *aStatus = nsEventStatus_eIgnore;
953
954 if (aEvent->mClass == eQueryContentEventClass) {
955 HandleQueryContentEvent(aEvent->AsQueryContentEvent());
956 return NS_OK;
957 }
958
959 WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
960 if (touchEvent && mInTouchDrag) {
961 if (touchEvent->mMessage == eTouchMove) {
962 GenerateDragGesture(aPresContext, touchEvent);
963 } else {
964 mInTouchDrag = false;
965 StopTrackingDragGesture(true);
966 }
967 }
968
969 if (mMouseEnterLeaveHelper && aEvent->IsTrusted()) {
970 // When the last `mouseover` event target is removed from the document,
971 // we makes mMouseEnterLeaveHelper update the last deepest `mouseenter`
972 // event target to the removed node parent and mark it as not the following
973 // `mouseout` event target. However, the other browsers may dispatch
974 // `mouseout` on it if it's restored "immediately". Therefore, we use
975 // the next animation frame as the deadline. ContentRemoved() enqueues a
976 // synthesized `mousemove` to dispatch mouse boundary events under the
977 // mouse cursor soon and the synthesized event (or eMouseExitFromWidget if
978 // our window is moved) will reach here at latest the next animation frame.
979 // Therefore, we can use the event as the deadline. If the removed last
980 // `mouseover` target is reconnected before a synthesized mouse event or
981 // a real mouse event, let's restore it as the following `mouseout` event
982 // target. Otherwise, e.g., a keyboard event, let's forget it.
983 mMouseEnterLeaveHelper->TryToRestorePendingRemovedOverTarget(aEvent);
984 }
985
986 static constexpr auto const allowSynthesisForTests = []() -> bool {
987 nsCOMPtr<nsIDragService> dragService =
988 do_GetService("@mozilla.org/widget/dragservice;1");
989 return dragService &&
990 !dragService->GetNeverAllowSessionIsSynthesizedForTests();
991 };
992
993 switch (aEvent->mMessage) {
994 case eContextMenu:
995 if (PointerLockManager::IsLocked()) {
996 return NS_ERROR_DOM_INVALID_STATE_ERR;
997 }
998 break;
999 case eMouseTouchDrag:
1000 mInTouchDrag = true;
1001 BeginTrackingDragGesture(aPresContext, mouseEvent, aTargetFrame);
1002 break;
1003 case eMouseDown: {
1004 switch (mouseEvent->mButton) {
1005 case MouseButton::ePrimary:
1006 BeginTrackingDragGesture(aPresContext, mouseEvent, aTargetFrame);
1007 mLastLeftMouseDownInfo.mClickCount = mouseEvent->mClickCount;
1008 SetClickCount(mouseEvent, aStatus);
1009 sNormalLMouseEventInProcess = true;
1010 break;
1011 case MouseButton::eMiddle:
1012 mLastMiddleMouseDownInfo.mClickCount = mouseEvent->mClickCount;
1013 SetClickCount(mouseEvent, aStatus);
1014 break;
1015 case MouseButton::eSecondary:
1016 mLastRightMouseDownInfo.mClickCount = mouseEvent->mClickCount;
1017 SetClickCount(mouseEvent, aStatus);
1018 break;
1019 }
1020 if (!StaticPrefs::dom_popup_experimental()) {
1021 NotifyTargetUserActivation(aEvent, aTargetContent);
1022 }
1023 break;
1024 }
1025 case eMouseUp: {
1026 switch (mouseEvent->mButton) {
1027 case MouseButton::ePrimary:
1028 if (StaticPrefs::ui_click_hold_context_menus()) {
1029 KillClickHoldTimer();
1030 }
1031 mInTouchDrag = false;
1032 StopTrackingDragGesture(true);
1033 sNormalLMouseEventInProcess = false;
1034 // then fall through...
1035 [[fallthrough]];
1036 case MouseButton::eSecondary:
1037 case MouseButton::eMiddle:
1038 RefPtr<EventStateManager> esm =
1039 ESMFromContentOrThis(aOverrideClickTarget);
1040 esm->SetClickCount(mouseEvent, aStatus, aOverrideClickTarget);
1041 break;
1042 }
1043 break;
1044 }
1045 case eMouseEnterIntoWidget:
1046 PointerEventHandler::UpdateActivePointerState(mouseEvent, aTargetContent);
1047 // In some cases on e10s eMouseEnterIntoWidget
1048 // event was sent twice into child process of content.
1049 // (From specific widget code (sending is not permanent) and
1050 // from ESM::DispatchMouseOrPointerBoundaryEvent (sending is permanent)).
1051 // IsCrossProcessForwardingStopped() helps to suppress sending accidental
1052 // event from widget code.
1053 aEvent->StopCrossProcessForwarding();
1054 break;
1055 case eMouseExitFromWidget:
1056 // If this is a remote frame, we receive eMouseExitFromWidget from the
1057 // parent the mouse exits our content. Since the parent may update the
1058 // cursor while the mouse is outside our frame, and since PuppetWidget
1059 // caches the current cursor internally, re-entering our content (say from
1060 // over a window edge) wont update the cursor if the cached value and the
1061 // current cursor match. So when the mouse exits a remote frame, clear the
1062 // cached widget cursor so a proper update will occur when the mouse
1063 // re-enters.
1064 if (XRE_IsContentProcess()) {
1065 ClearCachedWidgetCursor(mCurrentTarget);
1066 }
1067
1068 // IsCrossProcessForwardingStopped() helps to suppress double event
1069 // sending into process of content. For more information see comment
1070 // above, at eMouseEnterIntoWidget case.
1071 aEvent->StopCrossProcessForwarding();
1072
1073 // If the event is not a top-level window or puppet widget exit, then it's
1074 // not really an exit --- we may have traversed widget boundaries but
1075 // we're still in our toplevel window or puppet widget.
1076 if (mouseEvent->mExitFrom.value() !=
1077 WidgetMouseEvent::ePlatformTopLevel &&
1078 mouseEvent->mExitFrom.value() != WidgetMouseEvent::ePuppet) {
1079 // Treat it as a synthetic move so we don't generate spurious
1080 // "exit" or "move" events. Any necessary "out" or "over" events
1081 // will be generated by GenerateMouseEnterExit
1082 mouseEvent->mMessage = eMouseMove;
1083 mouseEvent->mReason = WidgetMouseEvent::eSynthesized;
1084 // then fall through...
1085 } else {
1086 MOZ_ASSERT_IF(XRE_IsParentProcess(),do { if (XRE_IsParentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePlatformTopLevel)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1088); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
")"); do { *((volatile int*)__null) = 1088; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1087 mouseEvent->mExitFrom.value() ==do { if (XRE_IsParentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePlatformTopLevel)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1088); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
")"); do { *((volatile int*)__null) = 1088; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1088 WidgetMouseEvent::ePlatformTopLevel)do { if (XRE_IsParentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePlatformTopLevel)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1088); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePlatformTopLevel"
")"); do { *((volatile int*)__null) = 1088; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1089 MOZ_ASSERT_IF(XRE_IsContentProcess(), mouseEvent->mExitFrom.value() ==do { if (XRE_IsContentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePuppet)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mouseEvent->mExitFrom.value
() == WidgetMouseEvent::ePuppet))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1090); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
")"); do { *((volatile int*)__null) = 1090; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1090 WidgetMouseEvent::ePuppet)do { if (XRE_IsContentProcess()) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(mouseEvent->mExitFrom
.value() == WidgetMouseEvent::ePuppet)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mouseEvent->mExitFrom.value
() == WidgetMouseEvent::ePuppet))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1090); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
")"); do { *((volatile int*)__null) = 1090; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1091 // We should synthetize corresponding pointer events
1092 GeneratePointerEnterExit(ePointerLeave, mouseEvent);
1093 GenerateMouseEnterExit(mouseEvent);
1094 // This is really an exit and should stop here
1095 aEvent->mMessage = eVoidEvent;
1096 break;
1097 }
1098 [[fallthrough]];
1099 case eMouseMove:
1100 case ePointerDown:
1101 if (aEvent->mMessage == ePointerDown) {
1102 PointerEventHandler::UpdateActivePointerState(mouseEvent,
1103 aTargetContent);
1104 PointerEventHandler::ImplicitlyCapturePointer(aTargetFrame, aEvent);
1105 if (StaticPrefs::dom_popup_experimental()) {
1106 // https://html.spec.whatwg.org/multipage/interaction.html#activation-triggering-input-event
1107 if (mouseEvent->mInputSource ==
1108 MouseEvent_Binding::MOZ_SOURCE_MOUSE) {
1109 NotifyTargetUserActivation(aEvent, aTargetContent);
1110 }
1111 } else if (mouseEvent->mInputSource !=
1112 MouseEvent_Binding::MOZ_SOURCE_TOUCH) {
1113 NotifyTargetUserActivation(aEvent, aTargetContent);
1114 }
1115
1116 LightDismissOpenPopovers(aEvent, aTargetContent);
1117 }
1118 [[fallthrough]];
1119 case ePointerMove: {
1120 if (!mInTouchDrag &&
1121 PointerEventHandler::IsDragAndDropEnabled(*mouseEvent)) {
1122 GenerateDragGesture(aPresContext, mouseEvent);
1123 }
1124 // on the Mac, GenerateDragGesture() may not return until the drag
1125 // has completed and so |aTargetFrame| may have been deleted (moving
1126 // a bookmark, for example). If this is the case, however, we know
1127 // that ClearFrameRefs() has been called and it cleared out
1128 // |mCurrentTarget|. As a result, we should pass |mCurrentTarget|
1129 // into UpdateCursor().
1130 UpdateCursor(aPresContext, mouseEvent, mCurrentTarget, aStatus);
1131
1132 UpdateLastRefPointOfMouseEvent(mouseEvent);
1133 if (PointerLockManager::IsLocked()) {
1134 ResetPointerToWindowCenterWhilePointerLocked(mouseEvent);
1135 }
1136 UpdateLastPointerPosition(mouseEvent);
1137
1138 GenerateMouseEnterExit(mouseEvent);
1139 // Flush pending layout changes, so that later mouse move events
1140 // will go to the right nodes.
1141 FlushLayout(aPresContext);
1142 break;
1143 }
1144 case ePointerUp:
1145 LightDismissOpenPopovers(aEvent, aTargetContent);
1146 GenerateMouseEnterExit(mouseEvent);
1147 if (StaticPrefs::dom_popup_experimental() &&
1148 mouseEvent->mInputSource != MouseEvent_Binding::MOZ_SOURCE_MOUSE) {
1149 NotifyTargetUserActivation(aEvent, aTargetContent);
1150 }
1151 break;
1152 case ePointerGotCapture:
1153 GenerateMouseEnterExit(mouseEvent);
1154 break;
1155 case eDragStart:
1156 if (StaticPrefs::ui_click_hold_context_menus()) {
1157 // an external drag gesture event came in, not generated internally
1158 // by Gecko. Make sure we get rid of the click-hold timer.
1159 KillClickHoldTimer();
1160 }
1161 break;
1162 case eDragOver: {
1163 WidgetDragEvent* dragEvent = aEvent->AsDragEvent();
1164 MOZ_ASSERT(dragEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(dragEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(dragEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("dragEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1164); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dragEvent" ")"
); do { *((volatile int*)__null) = 1164; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1165 if (dragEvent->mFlags.mIsSynthesizedForTests &&
1166 allowSynthesisForTests()) {
1167 dragEvent->InitDropEffectForTests();
1168 }
1169 // Send the enter/exit events before eDrop.
1170 GenerateDragDropEnterExit(aPresContext, dragEvent);
1171 break;
1172 }
1173 case eDrop: {
1174 if (aEvent->mFlags.mIsSynthesizedForTests && allowSynthesisForTests()) {
1175 MOZ_ASSERT(aEvent->AsDragEvent())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->AsDragEvent())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->AsDragEvent()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->AsDragEvent()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1175); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->AsDragEvent()"
")"); do { *((volatile int*)__null) = 1175; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1176 aEvent->AsDragEvent()->InitDropEffectForTests();
1177 }
1178 break;
1179 }
1180 case eKeyPress: {
1181 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
1182 if (keyEvent->ModifiersMatchWithAccessKey(AccessKeyType::eChrome) ||
1183 keyEvent->ModifiersMatchWithAccessKey(AccessKeyType::eContent)) {
1184 // If the eKeyPress event will be sent to a remote process, this
1185 // process needs to wait reply from the remote process for checking if
1186 // preceding eKeyDown event is consumed. If preceding eKeyDown event
1187 // is consumed in the remote process, BrowserChild won't send the event
1188 // back to this process. So, only when this process receives a reply
1189 // eKeyPress event in BrowserParent, we should handle accesskey in this
1190 // process.
1191 if (IsTopLevelRemoteTarget(GetFocusedElement())) {
1192 // However, if there is no accesskey target for the key combination,
1193 // we don't need to wait reply from the remote process. Otherwise,
1194 // Mark the event as waiting reply from remote process and stop
1195 // propagation in this process.
1196 if (CheckIfEventMatchesAccessKey(keyEvent, aPresContext)) {
1197 keyEvent->StopPropagation();
1198 keyEvent->MarkAsWaitingReplyFromRemoteProcess();
1199 }
1200 }
1201 // If the event target is in this process, we can handle accesskey now
1202 // since if preceding eKeyDown event was consumed, eKeyPress event
1203 // won't be dispatched by widget. So, coming eKeyPress event means
1204 // that the preceding eKeyDown event wasn't consumed in this case.
1205 else {
1206 AutoTArray<uint32_t, 10> accessCharCodes;
1207 keyEvent->GetAccessKeyCandidates(accessCharCodes);
1208
1209 if (HandleAccessKey(keyEvent, aPresContext, accessCharCodes)) {
1210 *aStatus = nsEventStatus_eConsumeNoDefault;
1211 }
1212 }
1213 }
1214 }
1215 // then fall through...
1216 [[fallthrough]];
1217 case eKeyDown:
1218 if (aEvent->mMessage == eKeyDown) {
1219 NotifyTargetUserActivation(aEvent, aTargetContent);
1220 }
1221 [[fallthrough]];
1222 case eKeyUp: {
1223 Element* element = GetFocusedElement();
1224 if (element) {
1225 mCurrentTargetContent = element;
1226 }
1227
1228 // NOTE: Don't refer TextComposition::IsComposing() since UI Events
1229 // defines that KeyboardEvent.isComposing is true when it's
1230 // dispatched after compositionstart and compositionend.
1231 // TextComposition::IsComposing() is false even before
1232 // compositionend if there is no composing string.
1233 // And also don't expose other document's composition state.
1234 // A native IME context is typically shared by multiple documents.
1235 // So, don't use GetTextCompositionFor(nsIWidget*) here.
1236 RefPtr<TextComposition> composition =
1237 IMEStateManager::GetTextCompositionFor(aPresContext);
1238 aEvent->AsKeyboardEvent()->mIsComposing = !!composition;
1239
1240 // Widget may need to perform default action for specific keyboard
1241 // event if it's not consumed. In this case, widget has already marked
1242 // the event as "waiting reply from remote process". However, we need
1243 // to reset it if the target (focused content) isn't in a remote process
1244 // because PresShell needs to check if it's marked as so before
1245 // dispatching events into the DOM tree.
1246 if (aEvent->IsWaitingReplyFromRemoteProcess() &&
1247 !aEvent->PropagationStopped() && !IsTopLevelRemoteTarget(element)) {
1248 aEvent->ResetWaitingReplyFromRemoteProcessState();
1249 }
1250 } break;
1251 case eWheel:
1252 case eWheelOperationStart:
1253 case eWheelOperationEnd: {
1254 NS_ASSERTION(aEvent->IsTrusted(),do { if (!(aEvent->IsTrusted())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Untrusted wheel event shouldn't be here", "aEvent->IsTrusted()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1255); MOZ_PretendNoReturn(); } } while (0)
1255 "Untrusted wheel event shouldn't be here")do { if (!(aEvent->IsTrusted())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Untrusted wheel event shouldn't be here", "aEvent->IsTrusted()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1255); MOZ_PretendNoReturn(); } } while (0)
;
1256 using DeltaModeCheckingState = WidgetWheelEvent::DeltaModeCheckingState;
1257
1258 if (Element* element = GetFocusedElement()) {
1259 mCurrentTargetContent = element;
1260 }
1261
1262 if (aEvent->mMessage != eWheel) {
1263 break;
1264 }
1265
1266 WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
1267 WheelPrefs::GetInstance()->ApplyUserPrefsToDelta(wheelEvent);
1268
1269 // If we won't dispatch a DOM event for this event, nothing to do anymore.
1270 if (!wheelEvent->IsAllowedToDispatchDOMEvent()) {
1271 break;
1272 }
1273
1274 if (StaticPrefs::dom_event_wheel_deltaMode_lines_always_disabled()) {
1275 wheelEvent->mDeltaModeCheckingState = DeltaModeCheckingState::Unchecked;
1276 } else if (ShouldAlwaysUseLineDeltas()) {
1277 wheelEvent->mDeltaModeCheckingState = DeltaModeCheckingState::Checked;
1278 } else {
1279 wheelEvent->mDeltaModeCheckingState = DeltaModeCheckingState::Unknown;
1280 }
1281
1282 // Init lineOrPageDelta values for line scroll events for some devices
1283 // on some platforms which might dispatch wheel events which don't
1284 // have lineOrPageDelta values. And also, if delta values are
1285 // customized by prefs, this recomputes them.
1286 DeltaAccumulator::GetInstance()->InitLineOrPageDelta(aTargetFrame, this,
1287 wheelEvent);
1288 } break;
1289 case eSetSelection: {
1290 RefPtr<Element> focuedElement = GetFocusedElement();
1291 IMEStateManager::HandleSelectionEvent(aPresContext, focuedElement,
1292 aEvent->AsSelectionEvent());
1293 break;
1294 }
1295 case eContentCommandCut:
1296 case eContentCommandCopy:
1297 case eContentCommandPaste:
1298 case eContentCommandDelete:
1299 case eContentCommandUndo:
1300 case eContentCommandRedo:
1301 case eContentCommandPasteTransferable:
1302 case eContentCommandLookUpDictionary:
1303 DoContentCommandEvent(aEvent->AsContentCommandEvent());
1304 break;
1305 case eContentCommandInsertText:
1306 DoContentCommandInsertTextEvent(aEvent->AsContentCommandEvent());
1307 break;
1308 case eContentCommandReplaceText:
1309 DoContentCommandReplaceTextEvent(aEvent->AsContentCommandEvent());
1310 break;
1311 case eContentCommandScroll:
1312 DoContentCommandScrollEvent(aEvent->AsContentCommandEvent());
1313 break;
1314 case eCompositionStart:
1315 if (aEvent->IsTrusted()) {
1316 // If the event is trusted event, set the selected text to data of
1317 // composition event.
1318 WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent();
1319 WidgetQueryContentEvent querySelectedTextEvent(
1320 true, eQuerySelectedText, compositionEvent->mWidget);
1321 HandleQueryContentEvent(&querySelectedTextEvent);
1322 if (querySelectedTextEvent.FoundSelection()) {
1323 compositionEvent->mData = querySelectedTextEvent.mReply->DataRef();
1324 }
1325 NS_ASSERTION(querySelectedTextEvent.Succeeded(),do { if (!(querySelectedTextEvent.Succeeded())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Failed to get selected text", "querySelectedTextEvent.Succeeded()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1326); MOZ_PretendNoReturn(); } } while (0)
1326 "Failed to get selected text")do { if (!(querySelectedTextEvent.Succeeded())) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Failed to get selected text", "querySelectedTextEvent.Succeeded()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1326); MOZ_PretendNoReturn(); } } while (0)
;
1327 }
1328 break;
1329 case eTouchStart:
1330 SetGestureDownPoint(aEvent->AsTouchEvent());
1331 break;
1332 case eTouchEnd:
1333 if (!StaticPrefs::dom_popup_experimental()) {
1334 NotifyTargetUserActivation(aEvent, aTargetContent);
1335 }
1336 break;
1337 default:
1338 break;
1339 }
1340 return NS_OK;
1341}
1342
1343// Returns true if this event is likely an user activation for a link or
1344// a link-like button, where modifier keys are likely be used for controlling
1345// where the link is opened.
1346//
1347// The modifiers associated with the user activation is used for controlling
1348// where the `window.open` is opened into.
1349static bool CanReflectModifiersToUserActivation(WidgetInputEvent* aEvent) {
1350 if (StaticPrefs::dom_popup_experimental()) {
1351 MOZ_ASSERT(aEvent->mMessage == eKeyDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1353); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1353; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1352 aEvent->mMessage == ePointerDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1353); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1353; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1353 aEvent->mMessage == ePointerUp)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1353); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1353; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1354 } else {
1355 MOZ_ASSERT(aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1357); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1357; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1356 aEvent->mMessage == ePointerDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1357); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1357; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1357 aEvent->mMessage == eTouchEnd)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1357); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1357; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1358 }
1359
1360 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
1361 if (keyEvent) {
1362 return keyEvent->CanReflectModifiersToUserActivation();
1363 }
1364
1365 return true;
1366}
1367
1368void EventStateManager::NotifyTargetUserActivation(WidgetEvent* aEvent,
1369 nsIContent* aTargetContent) {
1370 if (!aEvent->IsTrusted()) {
1371 return;
1372 }
1373
1374 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
1375 if (mouseEvent && !mouseEvent->IsReal()) {
1376 return;
1377 }
1378
1379 nsCOMPtr<nsINode> node = aTargetContent;
1380 if (!node) {
1381 return;
1382 }
1383
1384 Document* doc = node->OwnerDoc();
1385 if (!doc) {
1386 return;
1387 }
1388
1389 // Don't gesture activate for key events for keys which are likely
1390 // to be interaction with the browser, OS.
1391 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
1392 if (keyEvent && !keyEvent->CanUserGestureActivateTarget()) {
1393 return;
1394 }
1395
1396 // Touch gestures that end outside the drag target were touches that turned
1397 // into scroll/pan/swipe actions. We don't want to gesture activate on such
1398 // actions, we want to only gesture activate on touches that are taps.
1399 // That is, touches that end in roughly the same place that they started.
1400 if ((aEvent->mMessage == eTouchEnd ||
1401 (aEvent->mMessage == ePointerUp &&
1402 aEvent->AsPointerEvent()->mInputSource ==
1403 MouseEvent_Binding::MOZ_SOURCE_TOUCH)) &&
1404 IsEventOutsideDragThreshold(aEvent->AsInputEvent())) {
1405 return;
1406 }
1407
1408 // Do not treat the click on scrollbar as a user interaction with the web
1409 // content.
1410 if (StaticPrefs::dom_user_activation_ignore_scrollbars() &&
1411 ((StaticPrefs::dom_popup_experimental() &&
1412 (aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp)) ||
1413 (!StaticPrefs::dom_popup_experimental() &&
1414 (aEvent->mMessage == eMouseDown ||
1415 aEvent->mMessage == ePointerDown))) &&
1416 aTargetContent->IsInNativeAnonymousSubtree()) {
1417 nsIContent* current = aTargetContent;
1418 do {
1419 nsIContent* root = current->GetClosestNativeAnonymousSubtreeRoot();
1420 if (!root) {
1421 break;
1422 }
1423 if (root->IsXULElement(nsGkAtoms::scrollbar)) {
1424 return;
1425 }
1426 current = root->GetParent();
1427 } while (current);
1428 }
1429
1430#ifdef DEBUG1
1431 if (StaticPrefs::dom_popup_experimental()) {
1432 MOZ_ASSERT(aEvent->mMessage == eKeyDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1434); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1434; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1433 aEvent->mMessage == ePointerDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1434); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1434; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1434 aEvent->mMessage == ePointerUp)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== ePointerDown || aEvent->mMessage == ePointerUp)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1434); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
")"); do { *((volatile int*)__null) = 1434; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1435 } else {
1436 MOZ_ASSERT(aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1438); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1438; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1437 aEvent->mMessage == ePointerDown ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1438); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1438; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1438 aEvent->mMessage == eTouchEnd)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eKeyDown || aEvent->mMessage
== eMouseDown || aEvent->mMessage == ePointerDown || aEvent
->mMessage == eTouchEnd)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eKeyDown
|| aEvent->mMessage == eMouseDown || aEvent->mMessage ==
ePointerDown || aEvent->mMessage == eTouchEnd))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1438); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eKeyDown || aEvent->mMessage == eMouseDown || aEvent->mMessage == ePointerDown || aEvent->mMessage == eTouchEnd"
")"); do { *((volatile int*)__null) = 1438; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1439 }
1440#endif
1441
1442 UserActivation::Modifiers modifiers;
1443 if (WidgetInputEvent* inputEvent = aEvent->AsInputEvent()) {
1444 if (CanReflectModifiersToUserActivation(inputEvent)) {
1445 if (inputEvent->IsShift()) {
1446 modifiers.SetShift();
1447 }
1448 if (inputEvent->IsMeta()) {
1449 modifiers.SetMeta();
1450 }
1451 if (inputEvent->IsControl()) {
1452 modifiers.SetControl();
1453 }
1454 if (inputEvent->IsAlt()) {
1455 modifiers.SetAlt();
1456 }
1457
1458 WidgetMouseEvent* mouseEvent = inputEvent->AsMouseEvent();
1459 if (mouseEvent) {
1460 if (mouseEvent->mButton == MouseButton::eMiddle) {
1461 modifiers.SetMiddleMouse();
1462 }
1463 }
1464 }
1465 }
1466 doc->NotifyUserGestureActivation(modifiers);
1467}
1468
1469// https://html.spec.whatwg.org/multipage/popover.html#popover-light-dismiss
1470void EventStateManager::LightDismissOpenPopovers(WidgetEvent* aEvent,
1471 nsIContent* aTargetContent) {
1472 MOZ_ASSERT(aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == ePointerDown || aEvent->mMessage
== ePointerUp)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
" (" "Light dismiss must be called for pointer up/down only"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
") (" "Light dismiss must be called for pointer up/down only"
")"); do { *((volatile int*)__null) = 1473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1473 "Light dismiss must be called for pointer up/down only")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == ePointerDown || aEvent->mMessage
== ePointerUp)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aEvent->mMessage == ePointerDown
|| aEvent->mMessage == ePointerUp))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
" (" "Light dismiss must be called for pointer up/down only"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1473); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == ePointerDown || aEvent->mMessage == ePointerUp"
") (" "Light dismiss must be called for pointer up/down only"
")"); do { *((volatile int*)__null) = 1473; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1474
1475 if (!aEvent->IsTrusted() || !aTargetContent) {
1476 return;
1477 }
1478
1479 Element* topmostPopover = aTargetContent->OwnerDoc()->GetTopmostAutoPopover();
1480 if (!topmostPopover) {
1481 return;
1482 }
1483
1484 // Pointerdown: set document's popover pointerdown target to the result of
1485 // running topmost clicked popover given target.
1486 if (aEvent->mMessage == ePointerDown) {
1487 mPopoverPointerDownTarget = aTargetContent->GetTopmostClickedPopover();
1488 return;
1489 }
1490
1491 // Pointerup: hide open popovers.
1492 RefPtr<nsINode> ancestor = aTargetContent->GetTopmostClickedPopover();
1493 bool sameTarget = mPopoverPointerDownTarget == ancestor;
1494 mPopoverPointerDownTarget = nullptr;
1495 if (!sameTarget) {
1496 return;
1497 }
1498
1499 if (!ancestor) {
1500 ancestor = aTargetContent->OwnerDoc();
1501 }
1502 RefPtr<Document> doc(ancestor->OwnerDoc());
1503 doc->HideAllPopoversUntil(*ancestor, false, true);
1504}
1505
1506already_AddRefed<EventStateManager> EventStateManager::ESMFromContentOrThis(
1507 nsIContent* aContent) {
1508 if (aContent) {
1509 PresShell* presShell = aContent->OwnerDoc()->GetPresShell();
1510 if (presShell) {
1511 nsPresContext* prescontext = presShell->GetPresContext();
1512 if (prescontext) {
1513 RefPtr<EventStateManager> esm = prescontext->EventStateManager();
1514 if (esm) {
1515 return esm.forget();
1516 }
1517 }
1518 }
1519 }
1520
1521 RefPtr<EventStateManager> esm = this;
1522 return esm.forget();
1523}
1524
1525EventStateManager::LastMouseDownInfo& EventStateManager::GetLastMouseDownInfo(
1526 int16_t aButton) {
1527 switch (aButton) {
1528 case MouseButton::ePrimary:
1529 return mLastLeftMouseDownInfo;
1530 case MouseButton::eMiddle:
1531 return mLastMiddleMouseDownInfo;
1532 case MouseButton::eSecondary:
1533 return mLastRightMouseDownInfo;
1534 default:
1535 MOZ_ASSERT_UNREACHABLE("This button shouldn't use this method")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"This button shouldn't use this method" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1535); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "This button shouldn't use this method"
")"); do { *((volatile int*)__null) = 1535; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1536 return mLastLeftMouseDownInfo;
1537 }
1538}
1539
1540void EventStateManager::HandleQueryContentEvent(
1541 WidgetQueryContentEvent* aEvent) {
1542 switch (aEvent->mMessage) {
1543 case eQuerySelectedText:
1544 case eQueryTextContent:
1545 case eQueryCaretRect:
1546 case eQueryTextRect:
1547 case eQueryEditorRect:
1548 if (!IsTargetCrossProcess(aEvent)) {
1549 break;
1550 }
1551 // Will not be handled locally, remote the event
1552 GetCrossProcessTarget()->HandleQueryContentEvent(*aEvent);
1553 return;
1554 // Following events have not been supported in e10s mode yet.
1555 case eQueryContentState:
1556 case eQuerySelectionAsTransferable:
1557 case eQueryCharacterAtPoint:
1558 case eQueryDOMWidgetHittest:
1559 case eQueryTextRectArray:
1560 case eQueryDropTargetHittest:
1561 break;
1562 default:
1563 return;
1564 }
1565
1566 // If there is an IMEContentObserver, we need to handle QueryContentEvent
1567 // with it.
1568 // eQueryDropTargetHittest is not really an IME event, though
1569 if (mIMEContentObserver && aEvent->mMessage != eQueryDropTargetHittest) {
1570 RefPtr<IMEContentObserver> contentObserver = mIMEContentObserver;
1571 contentObserver->HandleQueryContentEvent(aEvent);
1572 return;
1573 }
1574
1575 ContentEventHandler handler(mPresContext);
1576 handler.HandleQueryContentEvent(aEvent);
1577}
1578
1579static AccessKeyType GetAccessKeyTypeFor(nsISupports* aDocShell) {
1580 nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(aDocShell));
1581 if (!treeItem) {
1582 return AccessKeyType::eNone;
1583 }
1584
1585 switch (treeItem->ItemType()) {
1586 case nsIDocShellTreeItem::typeChrome:
1587 return AccessKeyType::eChrome;
1588 case nsIDocShellTreeItem::typeContent:
1589 return AccessKeyType::eContent;
1590 default:
1591 return AccessKeyType::eNone;
1592 }
1593}
1594
1595static bool IsAccessKeyTarget(Element* aElement, nsAString& aKey) {
1596 // Use GetAttr because we want Unicode case=insensitive matching
1597 // XXXbz shouldn't this be case-sensitive, per spec?
1598 nsString contentKey;
1599 if (!aElement || !aElement->GetAttr(nsGkAtoms::accesskey, contentKey) ||
1600 !contentKey.Equals(aKey, nsCaseInsensitiveStringComparator)) {
1601 return false;
1602 }
1603
1604 if (!aElement->IsXULElement()) {
1605 return true;
1606 }
1607
1608 // For XUL we do visibility checks.
1609 nsIFrame* frame = aElement->GetPrimaryFrame();
1610 if (!frame) {
1611 return false;
1612 }
1613
1614 if (frame->IsFocusable()) {
1615 return true;
1616 }
1617
1618 if (!frame->IsVisibleConsideringAncestors()) {
1619 return false;
1620 }
1621
1622 // XUL controls can be activated.
1623 nsCOMPtr<nsIDOMXULControlElement> control = aElement->AsXULControl();
1624 if (control) {
1625 return true;
1626 }
1627
1628 // XUL label elements are never focusable, so we need to check for them
1629 // explicitly before giving up.
1630 if (aElement->IsXULElement(nsGkAtoms::label)) {
1631 return true;
1632 }
1633
1634 return false;
1635}
1636
1637bool EventStateManager::CheckIfEventMatchesAccessKey(
1638 WidgetKeyboardEvent* aEvent, nsPresContext* aPresContext) {
1639 AutoTArray<uint32_t, 10> accessCharCodes;
1640 aEvent->GetAccessKeyCandidates(accessCharCodes);
1641 return WalkESMTreeToHandleAccessKey(aEvent, aPresContext, accessCharCodes,
1642 nullptr, eAccessKeyProcessingNormal,
1643 false);
1644}
1645
1646bool EventStateManager::LookForAccessKeyAndExecute(
1647 nsTArray<uint32_t>& aAccessCharCodes, bool aIsTrustedEvent, bool aIsRepeat,
1648 bool aExecute) {
1649 int32_t count, start = -1;
1650 if (Element* focusedElement = GetFocusedElement()) {
1651 start = mAccessKeys.IndexOf(focusedElement);
1652 if (start == -1 && focusedElement->IsInNativeAnonymousSubtree()) {
1653 start = mAccessKeys.IndexOf(Element::FromNodeOrNull(
1654 focusedElement->GetClosestNativeAnonymousSubtreeRootParentOrHost()));
1655 }
1656 }
1657 RefPtr<Element> element;
1658 int32_t length = mAccessKeys.Count();
1659 for (uint32_t i = 0; i < aAccessCharCodes.Length(); ++i) {
1660 uint32_t ch = aAccessCharCodes[i];
1661 nsAutoString accessKey;
1662 AppendUCS4ToUTF16(ch, accessKey);
1663 for (count = 1; count <= length; ++count) {
1664 // mAccessKeys always stores Element instances.
1665 MOZ_DIAGNOSTIC_ASSERT(length == mAccessKeys.Count())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(length == mAccessKeys.Count())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(length == mAccessKeys.Count(
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("length == mAccessKeys.Count()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1665); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "length == mAccessKeys.Count()"
")"); do { *((volatile int*)__null) = 1665; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1666 element = mAccessKeys[(start + count) % length];
1667 if (IsAccessKeyTarget(element, accessKey)) {
1668 if (!aExecute) {
1669 return true;
1670 }
1671 Document* doc = element->OwnerDoc();
1672 const bool shouldActivate = [&] {
1673 if (!StaticPrefs::accessibility_accesskeycausesactivation()) {
1674 return false;
1675 }
1676 if (aIsRepeat && nsContentUtils::IsChromeDoc(doc)) {
1677 return false;
1678 }
1679
1680 // XXXedgar, Bug 1700646, maybe we could use other data structure to
1681 // make searching target with same accesskey easier, and current setup
1682 // could not ensure we cycle the target with tree order.
1683 int32_t j = 0;
1684 while (++j < length) {
1685 Element* el = mAccessKeys[(start + count + j) % length];
1686 if (IsAccessKeyTarget(el, accessKey)) {
1687 return false;
1688 }
1689 }
1690 return true;
1691 }();
1692
1693 // TODO(bug 1641171): This shouldn't be needed if we considered the
1694 // accesskey combination properly.
1695 if (aIsTrustedEvent) {
1696 doc->NotifyUserGestureActivation();
1697 }
1698
1699 auto result =
1700 element->PerformAccesskey(shouldActivate, aIsTrustedEvent);
1701 if (result.isOk()) {
1702 if (result.unwrap() && aIsTrustedEvent) {
1703 // If this is a child process, inform the parent that we want the
1704 // focus, but pass false since we don't want to change the window
1705 // order.
1706 nsIDocShell* docShell = mPresContext->GetDocShell();
1707 nsCOMPtr<nsIBrowserChild> child =
1708 docShell ? docShell->GetBrowserChild() : nullptr;
1709 if (child) {
1710 child->SendRequestFocus(false, CallerType::System);
1711 }
1712 }
1713 return true;
1714 }
1715 }
1716 }
1717 }
1718 return false;
1719}
1720
1721// static
1722void EventStateManager::GetAccessKeyLabelPrefix(Element* aElement,
1723 nsAString& aPrefix) {
1724 aPrefix.Truncate();
1725 nsAutoString separator, modifierText;
1726 nsContentUtils::GetModifierSeparatorText(separator);
1727
1728 AccessKeyType accessKeyType =
1729 GetAccessKeyTypeFor(aElement->OwnerDoc()->GetDocShell());
1730 if (accessKeyType == AccessKeyType::eNone) {
1731 return;
1732 }
1733 Modifiers modifiers = WidgetKeyboardEvent::AccessKeyModifiers(accessKeyType);
1734 if (modifiers == MODIFIER_NONE) {
1735 return;
1736 }
1737
1738 if (modifiers & MODIFIER_CONTROL) {
1739 nsContentUtils::GetControlText(modifierText);
1740 aPrefix.Append(modifierText + separator);
1741 }
1742 if (modifiers & MODIFIER_META) {
1743 nsContentUtils::GetCommandOrWinText(modifierText);
1744 aPrefix.Append(modifierText + separator);
1745 }
1746 if (modifiers & MODIFIER_ALT) {
1747 nsContentUtils::GetAltText(modifierText);
1748 aPrefix.Append(modifierText + separator);
1749 }
1750 if (modifiers & MODIFIER_SHIFT) {
1751 nsContentUtils::GetShiftText(modifierText);
1752 aPrefix.Append(modifierText + separator);
1753 }
1754}
1755
1756struct MOZ_STACK_CLASS AccessKeyInfo {
1757 WidgetKeyboardEvent* event;
1758 nsTArray<uint32_t>& charCodes;
1759
1760 AccessKeyInfo(WidgetKeyboardEvent* aEvent, nsTArray<uint32_t>& aCharCodes)
1761 : event(aEvent), charCodes(aCharCodes) {}
1762};
1763
1764bool EventStateManager::WalkESMTreeToHandleAccessKey(
1765 WidgetKeyboardEvent* aEvent, nsPresContext* aPresContext,
1766 nsTArray<uint32_t>& aAccessCharCodes, nsIDocShellTreeItem* aBubbledFrom,
1767 ProcessingAccessKeyState aAccessKeyState, bool aExecute) {
1768 EnsureDocument(mPresContext);
1769 nsCOMPtr<nsIDocShell> docShell = aPresContext->GetDocShell();
1770 if (NS_WARN_IF(!docShell)NS_warn_if_impl(!docShell, "!docShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1770)
|| NS_WARN_IF(!mDocument)NS_warn_if_impl(!mDocument, "!mDocument", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1770)
) {
1771 return false;
1772 }
1773 AccessKeyType accessKeyType = GetAccessKeyTypeFor(docShell);
1774 if (accessKeyType == AccessKeyType::eNone) {
1775 return false;
1776 }
1777 // Alt or other accesskey modifier is down, we may need to do an accesskey.
1778 if (mAccessKeys.Count() > 0 &&
1779 aEvent->ModifiersMatchWithAccessKey(accessKeyType)) {
1780 // Someone registered an accesskey. Find and activate it.
1781 if (LookForAccessKeyAndExecute(aAccessCharCodes, aEvent->IsTrusted(),
1782 aEvent->mIsRepeat, aExecute)) {
1783 return true;
1784 }
1785 }
1786
1787 int32_t childCount;
1788 docShell->GetInProcessChildCount(&childCount);
1789 for (int32_t counter = 0; counter < childCount; counter++) {
1790 // Not processing the child which bubbles up the handling
1791 nsCOMPtr<nsIDocShellTreeItem> subShellItem;
1792 docShell->GetInProcessChildAt(counter, getter_AddRefs(subShellItem));
1793 if (aAccessKeyState == eAccessKeyProcessingUp &&
1794 subShellItem == aBubbledFrom) {
1795 continue;
1796 }
1797
1798 nsCOMPtr<nsIDocShell> subDS = do_QueryInterface(subShellItem);
1799 if (subDS && IsShellVisible(subDS)) {
1800 // Guarantee subPresShell lifetime while we're handling access key
1801 // since somebody may assume that it won't be deleted before the
1802 // corresponding nsPresContext and EventStateManager.
1803 RefPtr<PresShell> subPresShell = subDS->GetPresShell();
1804
1805 // Docshells need not have a presshell (eg. display:none
1806 // iframes, docshells in transition between documents, etc).
1807 if (!subPresShell) {
1808 // Oh, well. Just move on to the next child
1809 continue;
1810 }
1811
1812 RefPtr<nsPresContext> subPresContext = subPresShell->GetPresContext();
1813
1814 RefPtr<EventStateManager> esm =
1815 static_cast<EventStateManager*>(subPresContext->EventStateManager());
1816
1817 if (esm && esm->WalkESMTreeToHandleAccessKey(
1818 aEvent, subPresContext, aAccessCharCodes, nullptr,
1819 eAccessKeyProcessingDown, aExecute)) {
1820 return true;
1821 }
1822 }
1823 } // if end . checking all sub docshell ends here.
1824
1825 // bubble up the process to the parent docshell if necessary
1826 if (eAccessKeyProcessingDown != aAccessKeyState) {
1827 nsCOMPtr<nsIDocShellTreeItem> parentShellItem;
1828 docShell->GetInProcessParent(getter_AddRefs(parentShellItem));
1829 nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parentShellItem);
1830 if (parentDS) {
1831 // Guarantee parentPresShell lifetime while we're handling access key
1832 // since somebody may assume that it won't be deleted before the
1833 // corresponding nsPresContext and EventStateManager.
1834 RefPtr<PresShell> parentPresShell = parentDS->GetPresShell();
1835 NS_ASSERTION(parentPresShell,do { if (!(parentPresShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Our PresShell exists but the parent's does not?", "parentPresShell"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1836); MOZ_PretendNoReturn(); } } while (0)
1836 "Our PresShell exists but the parent's does not?")do { if (!(parentPresShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Our PresShell exists but the parent's does not?", "parentPresShell"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1836); MOZ_PretendNoReturn(); } } while (0)
;
1837
1838 RefPtr<nsPresContext> parentPresContext =
1839 parentPresShell->GetPresContext();
1840 NS_ASSERTION(parentPresContext, "PresShell without PresContext")do { if (!(parentPresContext)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "PresShell without PresContext", "parentPresContext", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1840); MOZ_PretendNoReturn(); } } while (0)
;
1841
1842 RefPtr<EventStateManager> esm = static_cast<EventStateManager*>(
1843 parentPresContext->EventStateManager());
1844 if (esm && esm->WalkESMTreeToHandleAccessKey(
1845 aEvent, parentPresContext, aAccessCharCodes, docShell,
1846 eAccessKeyProcessingDown, aExecute)) {
1847 return true;
1848 }
1849 }
1850 } // if end. bubble up process
1851
1852 // If the content access key modifier is pressed, try remote children
1853 if (aExecute &&
1854 aEvent->ModifiersMatchWithAccessKey(AccessKeyType::eContent) &&
1855 mDocument && mDocument->GetWindow()) {
1856 // If the focus is currently on a node with a BrowserParent, the key event
1857 // should've gotten forwarded to the child process and HandleAccessKey
1858 // called from there.
1859 if (BrowserParent::GetFrom(GetFocusedElement())) {
1860 // If access key may be only in remote contents, this method won't handle
1861 // access key synchronously. In this case, only reply event should reach
1862 // here.
1863 MOZ_ASSERT(aEvent->IsHandledInRemoteProcess() ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->IsHandledInRemoteProcess() || !aEvent->
IsWaitingReplyFromRemoteProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->IsHandledInRemoteProcess
() || !aEvent->IsWaitingReplyFromRemoteProcess()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aEvent->IsHandledInRemoteProcess() || !aEvent->IsWaitingReplyFromRemoteProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1864); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsHandledInRemoteProcess() || !aEvent->IsWaitingReplyFromRemoteProcess()"
")"); do { *((volatile int*)__null) = 1864; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1864 !aEvent->IsWaitingReplyFromRemoteProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->IsHandledInRemoteProcess() || !aEvent->
IsWaitingReplyFromRemoteProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->IsHandledInRemoteProcess
() || !aEvent->IsWaitingReplyFromRemoteProcess()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("aEvent->IsHandledInRemoteProcess() || !aEvent->IsWaitingReplyFromRemoteProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1864); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsHandledInRemoteProcess() || !aEvent->IsWaitingReplyFromRemoteProcess()"
")"); do { *((volatile int*)__null) = 1864; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1865 }
1866 // If focus is somewhere else, then we need to check the remote children.
1867 // However, if the event has already been handled in a remote process,
1868 // then, focus is moved from the remote process after posting the event.
1869 // In such case, we shouldn't retry to handle access keys in remote
1870 // processes.
1871 else if (!aEvent->IsHandledInRemoteProcess()) {
1872 AccessKeyInfo accessKeyInfo(aEvent, aAccessCharCodes);
1873 nsContentUtils::CallOnAllRemoteChildren(
1874 mDocument->GetWindow(),
1875 [&accessKeyInfo](BrowserParent* aBrowserParent) -> CallState {
1876 // Only forward accesskeys for the active tab.
1877 if (aBrowserParent->GetDocShellIsActive()) {
1878 // Even if there is no target for the accesskey in this process,
1879 // the event may match with a content accesskey. If so, the
1880 // keyboard event should be handled with reply event for
1881 // preventing double action. (e.g., Alt+Shift+F on Windows may
1882 // focus a content in remote and open "File" menu.)
1883 accessKeyInfo.event->StopPropagation();
1884 accessKeyInfo.event->MarkAsWaitingReplyFromRemoteProcess();
1885 aBrowserParent->HandleAccessKey(*accessKeyInfo.event,
1886 accessKeyInfo.charCodes);
1887 return CallState::Stop;
1888 }
1889
1890 return CallState::Continue;
1891 });
1892 }
1893 }
1894
1895 return false;
1896} // end of HandleAccessKey
1897
1898static BrowserParent* GetBrowserParentAncestor(BrowserParent* aBrowserParent) {
1899 MOZ_ASSERT(aBrowserParent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aBrowserParent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aBrowserParent))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aBrowserParent"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1899); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aBrowserParent"
")"); do { *((volatile int*)__null) = 1899; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1900
1901 BrowserBridgeParent* bbp = aBrowserParent->GetBrowserBridgeParent();
1902 if (!bbp) {
1903 return nullptr;
1904 }
1905
1906 return bbp->Manager();
1907}
1908
1909static void DispatchCrossProcessMouseExitEvents(WidgetMouseEvent* aMouseEvent,
1910 BrowserParent* aRemoteTarget,
1911 BrowserParent* aStopAncestor,
1912 bool aIsReallyExit) {
1913 MOZ_ASSERT(aMouseEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseEvent))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aMouseEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1913); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseEvent"
")"); do { *((volatile int*)__null) = 1913; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1914 MOZ_ASSERT(aRemoteTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRemoteTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aRemoteTarget))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aRemoteTarget",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1914); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRemoteTarget"
")"); do { *((volatile int*)__null) = 1914; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1915 MOZ_ASSERT(aRemoteTarget != aStopAncestor)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRemoteTarget != aStopAncestor)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aRemoteTarget != aStopAncestor
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aRemoteTarget != aStopAncestor", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1915); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRemoteTarget != aStopAncestor"
")"); do { *((volatile int*)__null) = 1915; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1916 MOZ_ASSERT_IF(aStopAncestor, nsContentUtils::GetCommonBrowserParentAncestor(do { if (aStopAncestor) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(nsContentUtils::GetCommonBrowserParentAncestor
( aRemoteTarget, aStopAncestor))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nsContentUtils::GetCommonBrowserParentAncestor
( aRemoteTarget, aStopAncestor)))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("nsContentUtils::GetCommonBrowserParentAncestor( aRemoteTarget, aStopAncestor)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1917); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::GetCommonBrowserParentAncestor( aRemoteTarget, aStopAncestor)"
")"); do { *((volatile int*)__null) = 1917; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
1917 aRemoteTarget, aStopAncestor))do { if (aStopAncestor) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(nsContentUtils::GetCommonBrowserParentAncestor
( aRemoteTarget, aStopAncestor))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nsContentUtils::GetCommonBrowserParentAncestor
( aRemoteTarget, aStopAncestor)))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("nsContentUtils::GetCommonBrowserParentAncestor( aRemoteTarget, aStopAncestor)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1917); AnnotateMozCrashReason("MOZ_ASSERT" "(" "nsContentUtils::GetCommonBrowserParentAncestor( aRemoteTarget, aStopAncestor)"
")"); do { *((volatile int*)__null) = 1917; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1918
1919 while (aRemoteTarget != aStopAncestor) {
1920 UniquePtr<WidgetMouseEvent> mouseExitEvent =
1921 CreateMouseOrPointerWidgetEvent(aMouseEvent, eMouseExitFromWidget,
1922 aMouseEvent->mRelatedTarget);
1923 mouseExitEvent->mExitFrom =
1924 Some(aIsReallyExit ? WidgetMouseEvent::ePuppet
1925 : WidgetMouseEvent::ePuppetParentToPuppetChild);
1926
1927 auto ContentReactsToPointerEvents = [](BrowserParent* aRemoteTarget) {
1928 if (Element* owner = aRemoteTarget->GetOwnerElement()) {
1929 if (nsSubDocumentFrame* subDocFrame =
1930 do_QueryFrame(owner->GetPrimaryFrame())) {
1931 return subDocFrame->ContentReactsToPointerEvents();
1932 }
1933 }
1934 return true;
1935 };
1936
1937 if (ContentReactsToPointerEvents(aRemoteTarget)) {
1938 aRemoteTarget->SendRealMouseEvent(*mouseExitEvent);
1939 }
1940
1941 aRemoteTarget = GetBrowserParentAncestor(aRemoteTarget);
1942 }
1943}
1944
1945void EventStateManager::DispatchCrossProcessEvent(WidgetEvent* aEvent,
1946 BrowserParent* aRemoteTarget,
1947 nsEventStatus* aStatus) {
1948 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1948); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 1948; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1949 MOZ_ASSERT(aRemoteTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aRemoteTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aRemoteTarget))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aRemoteTarget",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1949); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aRemoteTarget"
")"); do { *((volatile int*)__null) = 1949; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1950 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1950); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 1950; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1951
1952 BrowserParent* remote = aRemoteTarget;
1953
1954 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
1955 bool isContextMenuKey = mouseEvent && mouseEvent->IsContextMenuKeyEvent();
1956 if (aEvent->mClass == eKeyboardEventClass || isContextMenuKey) {
1957 // APZ attaches a LayersId to hit-testable events, for keyboard events,
1958 // we use focus.
1959 BrowserParent* preciseRemote = BrowserParent::GetFocused();
1960 if (preciseRemote) {
1961 remote = preciseRemote;
1962 }
1963 // else there is a race between layout and focus tracking,
1964 // so fall back to delivering the event to the topmost child process.
1965 } else if (aEvent->mLayersId.IsValid()) {
1966 BrowserParent* preciseRemote =
1967 BrowserParent::GetBrowserParentFromLayersId(aEvent->mLayersId);
1968 if (preciseRemote) {
1969 remote = preciseRemote;
1970 }
1971 // else there is a race between APZ and the LayersId to BrowserParent
1972 // mapping, so fall back to delivering the event to the topmost child
1973 // process.
1974 }
1975
1976 MOZ_ASSERT(aEvent->mMessage != ePointerClick)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage != ePointerClick)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage != ePointerClick
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aEvent->mMessage != ePointerClick", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1976); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage != ePointerClick"
")"); do { *((volatile int*)__null) = 1976; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1977 MOZ_ASSERT(aEvent->mMessage != ePointerAuxClick)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage != ePointerAuxClick)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aEvent->mMessage != ePointerAuxClick))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent->mMessage != ePointerAuxClick"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1977); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage != ePointerAuxClick"
")"); do { *((volatile int*)__null) = 1977; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1978
1979 // SendReal* will transform the coordinate to the child process coordinate
1980 // space. So restore the coordinate after the event has been dispatched to the
1981 // child process to avoid using the transformed coordinate afterward.
1982 AutoRestore<LayoutDeviceIntPoint> restore(aEvent->mRefPoint);
1983 switch (aEvent->mClass) {
1984 case ePointerEventClass:
1985 MOZ_ASSERT(aEvent->mMessage == eContextMenu)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eContextMenu)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mMessage == eContextMenu
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aEvent->mMessage == eContextMenu", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1985); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eContextMenu"
")"); do { *((volatile int*)__null) = 1985; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1986 [[fallthrough]];
1987 case eMouseEventClass: {
1988 BrowserParent* oldRemote = BrowserParent::GetLastMouseRemoteTarget();
1989
1990 // If this is a eMouseExitFromWidget event, need to redirect the event to
1991 // the last remote and and notify all its ancestors about the exit, if
1992 // any.
1993 if (mouseEvent->mMessage == eMouseExitFromWidget) {
1994 MOZ_ASSERT(mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mouseEvent->mExitFrom.value() == WidgetMouseEvent
::ePuppet)>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(mouseEvent->mExitFrom.value() ==
WidgetMouseEvent::ePuppet))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1994); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mExitFrom.value() == WidgetMouseEvent::ePuppet"
")"); do { *((volatile int*)__null) = 1994; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1995 MOZ_ASSERT(mouseEvent->mReason == WidgetMouseEvent::eReal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mouseEvent->mReason == WidgetMouseEvent::eReal)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mouseEvent->mReason == WidgetMouseEvent::eReal)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("mouseEvent->mReason == WidgetMouseEvent::eReal"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1995); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mReason == WidgetMouseEvent::eReal"
")"); do { *((volatile int*)__null) = 1995; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1996 MOZ_ASSERT(!mouseEvent->mLayersId.IsValid())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mouseEvent->mLayersId.IsValid())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mouseEvent->mLayersId.IsValid
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mouseEvent->mLayersId.IsValid()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1996); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mouseEvent->mLayersId.IsValid()"
")"); do { *((volatile int*)__null) = 1996; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1997 MOZ_ASSERT(remote->GetBrowserHost())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(remote->GetBrowserHost())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(remote->GetBrowserHost())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("remote->GetBrowserHost()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 1997); AnnotateMozCrashReason("MOZ_ASSERT" "(" "remote->GetBrowserHost()"
")"); do { *((volatile int*)__null) = 1997; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1998
1999 if (oldRemote && oldRemote != remote) {
2000 Unused << NS_WARN_IF(nsContentUtils::GetCommonBrowserParentAncestor(NS_warn_if_impl(nsContentUtils::GetCommonBrowserParentAncestor
( remote, oldRemote) != remote, "nsContentUtils::GetCommonBrowserParentAncestor( remote, oldRemote) != remote"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2001)
2001 remote, oldRemote) != remote)NS_warn_if_impl(nsContentUtils::GetCommonBrowserParentAncestor
( remote, oldRemote) != remote, "nsContentUtils::GetCommonBrowserParentAncestor( remote, oldRemote) != remote"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2001)
;
2002 remote = oldRemote;
2003 }
2004
2005 DispatchCrossProcessMouseExitEvents(mouseEvent, remote, nullptr, true);
2006 return;
2007 }
2008
2009 if (BrowserParent* pointerLockedRemote =
2010 PointerLockManager::GetLockedRemoteTarget()) {
2011 remote = pointerLockedRemote;
2012 } else if (BrowserParent* pointerCapturedRemote =
2013 PointerEventHandler::GetPointerCapturingRemoteTarget(
2014 mouseEvent->pointerId)) {
2015 remote = pointerCapturedRemote;
2016 } else if (BrowserParent* capturingRemote =
2017 PresShell::GetCapturingRemoteTarget()) {
2018 remote = capturingRemote;
2019 }
2020
2021 // If a mouse is over a remote target A, and then moves to
2022 // remote target B, we'd deliver the event directly to remote target B
2023 // after the moving, A would never get notified that the mouse left.
2024 // So we generate a exit event to notify A after the move.
2025 // XXXedgar, if the synthesized mouse events could deliver to the correct
2026 // process directly (see
2027 // https://bugzilla.mozilla.org/show_bug.cgi?id=1549355), we probably
2028 // don't need to check mReason then.
2029 if (mouseEvent->mReason == WidgetMouseEvent::eReal &&
2030 remote != oldRemote) {
2031 MOZ_ASSERT(mouseEvent->mMessage != eMouseExitFromWidget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mouseEvent->mMessage != eMouseExitFromWidget)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mouseEvent->mMessage != eMouseExitFromWidget))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mouseEvent->mMessage != eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2031); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mouseEvent->mMessage != eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 2031; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2032 if (oldRemote) {
2033 BrowserParent* commonAncestor =
2034 nsContentUtils::GetCommonBrowserParentAncestor(remote, oldRemote);
2035 if (commonAncestor == oldRemote) {
2036 // Mouse moves to the inner OOP frame, it is not a really exit.
2037 DispatchCrossProcessMouseExitEvents(
2038 mouseEvent, GetBrowserParentAncestor(remote),
2039 GetBrowserParentAncestor(commonAncestor), false);
2040 } else if (commonAncestor == remote) {
2041 // Mouse moves to the outer OOP frame, it is a really exit.
2042 DispatchCrossProcessMouseExitEvents(mouseEvent, oldRemote,
2043 commonAncestor, true);
2044 } else {
2045 // Mouse moves to OOP frame in other subtree, it is a really exit,
2046 // need to notify all its ancestors before common ancestor about the
2047 // exit.
2048 DispatchCrossProcessMouseExitEvents(mouseEvent, oldRemote,
2049 commonAncestor, true);
2050 if (commonAncestor) {
2051 UniquePtr<WidgetMouseEvent> mouseExitEvent =
2052 CreateMouseOrPointerWidgetEvent(mouseEvent,
2053 eMouseExitFromWidget,
2054 mouseEvent->mRelatedTarget);
2055 mouseExitEvent->mExitFrom =
2056 Some(WidgetMouseEvent::ePuppetParentToPuppetChild);
2057 commonAncestor->SendRealMouseEvent(*mouseExitEvent);
2058 }
2059 }
2060 }
2061
2062 if (mouseEvent->mMessage != eMouseExitFromWidget &&
2063 mouseEvent->mMessage != eMouseEnterIntoWidget) {
2064 // This is to make cursor would be updated correctly.
2065 remote->MouseEnterIntoWidget();
2066 }
2067 }
2068
2069 remote->SendRealMouseEvent(*mouseEvent);
2070 return;
2071 }
2072 case eKeyboardEventClass: {
2073 auto* keyboardEvent = aEvent->AsKeyboardEvent();
2074 if (aEvent->mMessage == eKeyUp) {
2075 HandleKeyUpInteraction(keyboardEvent);
2076 }
2077 remote->SendRealKeyEvent(*keyboardEvent);
2078 return;
2079 }
2080 case eWheelEventClass: {
2081 if (BrowserParent* pointerLockedRemote =
2082 PointerLockManager::GetLockedRemoteTarget()) {
2083 remote = pointerLockedRemote;
2084 }
2085 remote->SendMouseWheelEvent(*aEvent->AsWheelEvent());
2086 return;
2087 }
2088 case eTouchEventClass: {
2089 // Let the child process synthesize a mouse event if needed, and
2090 // ensure we don't synthesize one in this process.
2091 *aStatus = nsEventStatus_eConsumeNoDefault;
2092 remote->SendRealTouchEvent(*aEvent->AsTouchEvent());
2093 return;
2094 }
2095 case eDragEventClass: {
2096 RefPtr<BrowserParent> browserParent = remote;
2097 browserParent->MaybeInvokeDragSession(aEvent->mMessage);
2098
2099 RefPtr<nsIWidget> widget = browserParent->GetTopLevelWidget();
2100 nsCOMPtr<nsIDragSession> dragSession =
2101 nsContentUtils::GetDragSession(widget);
2102 uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
2103 uint32_t action = nsIDragService::DRAGDROP_ACTION_NONE;
2104 nsCOMPtr<nsIPrincipal> principal;
2105 nsCOMPtr<nsIContentSecurityPolicy> csp;
2106
2107 if (dragSession) {
2108 dragSession->DragEventDispatchedToChildProcess();
2109 dragSession->GetDragAction(&action);
2110 dragSession->GetTriggeringPrincipal(getter_AddRefs(principal));
2111 dragSession->GetCsp(getter_AddRefs(csp));
2112 RefPtr<DataTransfer> initialDataTransfer =
2113 dragSession->GetDataTransfer();
2114 if (initialDataTransfer) {
2115 dropEffect = initialDataTransfer->DropEffectInt();
2116 }
2117 }
2118
2119 browserParent->SendRealDragEvent(*aEvent->AsDragEvent(), action,
2120 dropEffect, principal, csp);
2121 return;
2122 }
2123 default: {
2124 MOZ_CRASH("Attempt to send non-whitelisted event?")do { do { } while (false); MOZ_ReportCrash("" "Attempt to send non-whitelisted event?"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2124); AnnotateMozCrashReason("MOZ_CRASH(" "Attempt to send non-whitelisted event?"
")"); do { *((volatile int*)__null) = 2124; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
2125 }
2126 }
2127}
2128
2129bool EventStateManager::IsRemoteTarget(nsIContent* target) {
2130 return BrowserParent::GetFrom(target) || BrowserBridgeChild::GetFrom(target);
2131}
2132
2133bool EventStateManager::IsTopLevelRemoteTarget(nsIContent* target) {
2134 return !!BrowserParent::GetFrom(target);
2135}
2136
2137bool EventStateManager::HandleCrossProcessEvent(WidgetEvent* aEvent,
2138 nsEventStatus* aStatus) {
2139 if (!aEvent->CanBeSentToRemoteProcess()) {
2140 return false;
2141 }
2142
2143 MOZ_ASSERT(!aEvent->HasBeenPostedToRemoteProcess(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEvent->HasBeenPostedToRemoteProcess())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aEvent->HasBeenPostedToRemoteProcess()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aEvent->HasBeenPostedToRemoteProcess()"
" (" "Why do we need to post same event to remote processes again?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2144); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aEvent->HasBeenPostedToRemoteProcess()"
") (" "Why do we need to post same event to remote processes again?"
")"); do { *((volatile int*)__null) = 2144; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2144 "Why do we need to post same event to remote processes again?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEvent->HasBeenPostedToRemoteProcess())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aEvent->HasBeenPostedToRemoteProcess()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aEvent->HasBeenPostedToRemoteProcess()"
" (" "Why do we need to post same event to remote processes again?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2144); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aEvent->HasBeenPostedToRemoteProcess()"
") (" "Why do we need to post same event to remote processes again?"
")"); do { *((volatile int*)__null) = 2144; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2145
2146 // Collect the remote event targets we're going to forward this
2147 // event to.
2148 //
2149 // NB: the elements of |remoteTargets| must be unique, for correctness.
2150 AutoTArray<RefPtr<BrowserParent>, 1> remoteTargets;
2151 if (aEvent->mClass != eTouchEventClass || aEvent->mMessage == eTouchStart) {
2152 // If this event only has one target, and it's remote, add it to
2153 // the array.
2154 nsIFrame* frame = aEvent->mMessage == eDragExit
2155 ? sLastDragOverFrame.GetFrame()
2156 : GetEventTarget();
2157 nsIContent* target = frame ? frame->GetContent() : nullptr;
2158 if (BrowserParent* remoteTarget = BrowserParent::GetFrom(target)) {
2159 remoteTargets.AppendElement(remoteTarget);
2160 }
2161 } else {
2162 // This is a touch event with possibly multiple touch points.
2163 // Each touch point may have its own target. So iterate through
2164 // all of them and collect the unique set of targets for event
2165 // forwarding.
2166 //
2167 // This loop is similar to the one used in
2168 // PresShell::DispatchTouchEvent().
2169 const WidgetTouchEvent::TouchArray& touches =
2170 aEvent->AsTouchEvent()->mTouches;
2171 for (uint32_t i = 0; i < touches.Length(); ++i) {
2172 Touch* touch = touches[i];
2173 // NB: the |mChanged| check is an optimization, subprocesses can
2174 // compute this for themselves. If the touch hasn't changed, we
2175 // may be able to avoid forwarding the event entirely (which is
2176 // not free).
2177 if (!touch || !touch->mChanged) {
2178 continue;
2179 }
2180 nsCOMPtr<EventTarget> targetPtr = touch->mTarget;
2181 if (!targetPtr) {
2182 continue;
2183 }
2184 nsCOMPtr<nsIContent> target = do_QueryInterface(targetPtr);
2185 BrowserParent* remoteTarget = BrowserParent::GetFrom(target);
2186 if (remoteTarget && !remoteTargets.Contains(remoteTarget)) {
2187 remoteTargets.AppendElement(remoteTarget);
2188 }
2189 }
2190 }
2191
2192 if (remoteTargets.Length() == 0) {
2193 return false;
2194 }
2195
2196 // Dispatch the event to the remote target.
2197 for (uint32_t i = 0; i < remoteTargets.Length(); ++i) {
2198 DispatchCrossProcessEvent(aEvent, remoteTargets[i], aStatus);
2199 }
2200 return aEvent->HasBeenPostedToRemoteProcess();
2201}
2202
2203//
2204// CreateClickHoldTimer
2205//
2206// Fire off a timer for determining if the user wants click-hold. This timer
2207// is a one-shot that will be cancelled when the user moves enough to fire
2208// a drag.
2209//
2210void EventStateManager::CreateClickHoldTimer(nsPresContext* inPresContext,
2211 nsIFrame* inDownFrame,
2212 WidgetGUIEvent* inMouseDownEvent) {
2213 if (!inMouseDownEvent->IsTrusted() ||
2214 IsTopLevelRemoteTarget(mGestureDownContent) ||
2215 PointerLockManager::IsLocked()) {
2216 return;
2217 }
2218
2219 // just to be anal (er, safe)
2220 if (mClickHoldTimer) {
2221 mClickHoldTimer->Cancel();
2222 mClickHoldTimer = nullptr;
2223 }
2224
2225 // if content clicked on has a popup, don't even start the timer
2226 // since we'll end up conflicting and both will show.
2227 if (mGestureDownContent &&
2228 nsContentUtils::HasNonEmptyAttr(mGestureDownContent, kNameSpaceID_None,
2229 nsGkAtoms::popup)) {
2230 return;
2231 }
2232
2233 int32_t clickHoldDelay = StaticPrefs::ui_click_hold_context_menus_delay();
2234 NS_NewTimerWithFuncCallback(
2235 getter_AddRefs(mClickHoldTimer), sClickHoldCallback, this, clickHoldDelay,
2236 nsITimer::TYPE_ONE_SHOT, "EventStateManager::CreateClickHoldTimer");
2237} // CreateClickHoldTimer
2238
2239//
2240// KillClickHoldTimer
2241//
2242// Stop the timer that would show the context menu dead in its tracks
2243//
2244void EventStateManager::KillClickHoldTimer() {
2245 if (mClickHoldTimer) {
2246 mClickHoldTimer->Cancel();
2247 mClickHoldTimer = nullptr;
2248 }
2249}
2250
2251//
2252// sClickHoldCallback
2253//
2254// This fires after the mouse has been down for a certain length of time.
2255//
2256void EventStateManager::sClickHoldCallback(nsITimer* aTimer, void* aESM) {
2257 RefPtr<EventStateManager> self = static_cast<EventStateManager*>(aESM);
2258 if (self) {
2259 self->FireContextClick();
2260 }
2261
2262 // NOTE: |aTimer| and |self->mAutoHideTimer| are invalid after calling
2263 // ClosePopup();
2264
2265} // sAutoHideCallback
2266
2267//
2268// FireContextClick
2269//
2270// If we're this far, our timer has fired, which means the mouse has been down
2271// for a certain period of time and has not moved enough to generate a
2272// dragGesture. We can be certain the user wants a context-click at this stage,
2273// so generate a dom event and fire it in.
2274//
2275// After the event fires, check if PreventDefault() has been set on the event
2276// which means that someone either ate the event or put up a context menu. This
2277// is our cue to stop tracking the drag gesture. If we always did this,
2278// draggable items w/out a context menu wouldn't be draggable after a certain
2279// length of time, which is _not_ what we want.
2280//
2281void EventStateManager::FireContextClick() {
2282 if (!mGestureDownContent || !mPresContext || PointerLockManager::IsLocked()) {
2283 return;
2284 }
2285
2286#ifdef XP_MACOSX
2287 // Hack to ensure that we don't show a context menu when the user
2288 // let go of the mouse after a long cpu-hogging operation prevented
2289 // us from handling any OS events. See bug 117589.
2290 if (!CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState,
2291 kCGMouseButtonLeft))
2292 return;
2293#endif
2294
2295 nsEventStatus status = nsEventStatus_eIgnore;
2296
2297 // Dispatch to the DOM. We have to fake out the ESM and tell it that the
2298 // current target frame is actually where the mouseDown occurred, otherwise it
2299 // will use the frame the mouse is currently over which may or may not be
2300 // the same. (Note: saari and I have decided that we don't have to reset
2301 // |mCurrentTarget| when we're through because no one else is doing anything
2302 // more with this event and it will get reset on the very next event to the
2303 // correct frame).
2304 mCurrentTarget = mPresContext->GetPrimaryFrameFor(mGestureDownContent);
2305 // make sure the widget sticks around
2306 nsCOMPtr<nsIWidget> targetWidget;
2307 if (mCurrentTarget && (targetWidget = mCurrentTarget->GetNearestWidget())) {
2308 NS_ASSERTION(do { if (!(mPresContext == mCurrentTarget->PresContext()))
{ NS_DebugBreak(NS_DEBUG_ASSERTION, "a prescontext returned a primary frame that didn't belong to it?"
, "mPresContext == mCurrentTarget->PresContext()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2310); MOZ_PretendNoReturn(); } } while (0)
2309 mPresContext == mCurrentTarget->PresContext(),do { if (!(mPresContext == mCurrentTarget->PresContext()))
{ NS_DebugBreak(NS_DEBUG_ASSERTION, "a prescontext returned a primary frame that didn't belong to it?"
, "mPresContext == mCurrentTarget->PresContext()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2310); MOZ_PretendNoReturn(); } } while (0)
2310 "a prescontext returned a primary frame that didn't belong to it?")do { if (!(mPresContext == mCurrentTarget->PresContext()))
{ NS_DebugBreak(NS_DEBUG_ASSERTION, "a prescontext returned a primary frame that didn't belong to it?"
, "mPresContext == mCurrentTarget->PresContext()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2310); MOZ_PretendNoReturn(); } } while (0)
;
2311
2312 // before dispatching, check that we're not on something that
2313 // doesn't get a context menu
2314 bool allowedToDispatch = true;
2315
2316 if (mGestureDownContent->IsAnyOfXULElements(nsGkAtoms::scrollbar,
2317 nsGkAtoms::scrollbarbutton,
2318 nsGkAtoms::button)) {
2319 allowedToDispatch = false;
2320 } else if (mGestureDownContent->IsXULElement(nsGkAtoms::toolbarbutton)) {
2321 // a <toolbarbutton> that has the container attribute set
2322 // will already have its own dropdown.
2323 if (nsContentUtils::HasNonEmptyAttr(
2324 mGestureDownContent, kNameSpaceID_None, nsGkAtoms::container)) {
2325 allowedToDispatch = false;
2326 } else {
2327 // If the toolbar button has an open menu, don't attempt to open
2328 // a second menu
2329 if (mGestureDownContent->IsElement() &&
2330 mGestureDownContent->AsElement()->AttrValueIs(
2331 kNameSpaceID_None, nsGkAtoms::open, nsGkAtoms::_true,
2332 eCaseMatters)) {
2333 allowedToDispatch = false;
2334 }
2335 }
2336 } else if (mGestureDownContent->IsHTMLElement()) {
2337 if (const auto* formCtrl =
2338 nsIFormControl::FromNode(mGestureDownContent)) {
2339 allowedToDispatch =
2340 formCtrl->IsTextControl(/*aExcludePassword*/ false) ||
2341 formCtrl->ControlType() == FormControlType::InputFile;
2342 } else if (mGestureDownContent->IsAnyOfHTMLElements(
2343 nsGkAtoms::embed, nsGkAtoms::object, nsGkAtoms::label)) {
2344 allowedToDispatch = false;
2345 }
2346 }
2347
2348 if (allowedToDispatch) {
2349 // init the event while mCurrentTarget is still good
2350 WidgetPointerEvent event(true, eContextMenu, targetWidget);
2351 event.mClickCount = 1;
2352 FillInEventFromGestureDown(&event);
2353
2354 // we need to forget the clicking content and click count for the
2355 // following eMouseUp event when click-holding context menus
2356 LastMouseDownInfo& mouseDownInfo = GetLastMouseDownInfo(event.mButton);
2357 mouseDownInfo.mLastMouseDownContent = nullptr;
2358 mouseDownInfo.mClickCount = 0;
2359 mouseDownInfo.mLastMouseDownInputControlType = Nothing();
2360
2361 // stop selection tracking, we're in control now
2362 if (mCurrentTarget) {
2363 RefPtr<nsFrameSelection> frameSel = mCurrentTarget->GetFrameSelection();
2364
2365 if (frameSel && frameSel->GetDragState()) {
2366 // note that this can cause selection changed events to fire if we're
2367 // in a text field, which will null out mCurrentTarget
2368 frameSel->SetDragState(false);
2369 }
2370 }
2371
2372 AutoHandlingUserInputStatePusher userInpStatePusher(true, &event);
2373
2374 // dispatch to DOM
2375 RefPtr<nsPresContext> presContext = mPresContext;
2376
2377 // The contextmenu event handled by PresShell will apply to elements (not
2378 // all nodes) correctly and will be dispatched to EventStateManager for
2379 // further handling preventing click event and stopping tracking drag
2380 // gesture.
2381 if (RefPtr<PresShell> presShell = presContext->GetPresShell()) {
2382 presShell->HandleEvent(mCurrentTarget, &event, false, &status);
2383 }
2384
2385 // We don't need to dispatch to frame handling because no frames
2386 // watch eContextMenu except for nsMenuFrame and that's only for
2387 // dismissal. That's just as well since we don't really know
2388 // which frame to send it to.
2389 }
2390 }
2391
2392 // stop tracking a drag whatever the event has been handled or not.
2393 StopTrackingDragGesture(true);
2394
2395 KillClickHoldTimer();
2396
2397} // FireContextClick
2398
2399//
2400// BeginTrackingDragGesture
2401//
2402// Record that the mouse has gone down and that we should move to TRACKING state
2403// of d&d gesture tracker.
2404//
2405// We also use this to track click-hold context menus. When the mouse goes down,
2406// fire off a short timer. If the timer goes off and we have yet to fire the
2407// drag gesture (ie, the mouse hasn't moved a certain distance), then we can
2408// assume the user wants a click-hold, so fire a context-click event. We only
2409// want to cancel the drag gesture if the context-click event is handled.
2410//
2411void EventStateManager::BeginTrackingDragGesture(nsPresContext* aPresContext,
2412 WidgetMouseEvent* inDownEvent,
2413 nsIFrame* inDownFrame) {
2414 if (!inDownEvent->mWidget) {
2415 return;
2416 }
2417
2418 // Note that |inDownEvent| could be either a mouse down event or a
2419 // synthesized mouse move event.
2420 SetGestureDownPoint(inDownEvent);
2421
2422 if (inDownFrame) {
2423 inDownFrame->GetContentForEvent(inDownEvent,
2424 getter_AddRefs(mGestureDownContent));
2425
2426 mGestureDownFrameOwner = inDownFrame->GetContent();
2427 if (!mGestureDownFrameOwner) {
2428 mGestureDownFrameOwner = mGestureDownContent;
2429 }
2430 }
2431 mGestureModifiers = inDownEvent->mModifiers;
2432 mGestureDownButtons = inDownEvent->mButtons;
2433 mGestureDownButton = inDownEvent->mButton;
2434
2435 if (inDownEvent->mMessage != eMouseTouchDrag &&
2436 StaticPrefs::ui_click_hold_context_menus()) {
2437 // fire off a timer to track click-hold
2438 CreateClickHoldTimer(aPresContext, inDownFrame, inDownEvent);
2439 }
2440}
2441
2442void EventStateManager::SetGestureDownPoint(WidgetGUIEvent* aEvent) {
2443 mGestureDownPoint =
2444 GetEventRefPoint(aEvent) + aEvent->mWidget->WidgetToScreenOffset();
2445}
2446
2447LayoutDeviceIntPoint EventStateManager::GetEventRefPoint(
2448 WidgetEvent* aEvent) const {
2449 auto touchEvent = aEvent->AsTouchEvent();
2450 return (touchEvent && !touchEvent->mTouches.IsEmpty())
2451 ? aEvent->AsTouchEvent()->mTouches[0]->mRefPoint
2452 : aEvent->mRefPoint;
2453}
2454
2455void EventStateManager::BeginTrackingRemoteDragGesture(
2456 nsIContent* aContent, RemoteDragStartData* aDragStartData) {
2457 mGestureDownContent = aContent;
2458 mGestureDownFrameOwner = aContent;
2459 mGestureDownInTextControl =
2460 aContent && aContent->IsInNativeAnonymousSubtree() &&
2461 TextControlElement::FromNodeOrNull(
2462 aContent->GetClosestNativeAnonymousSubtreeRootParentOrHost());
2463 mGestureDownDragStartData = aDragStartData;
2464}
2465
2466//
2467// StopTrackingDragGesture
2468//
2469// Record that the mouse has gone back up so that we should leave the TRACKING
2470// state of d&d gesture tracker and return to the START state.
2471//
2472void EventStateManager::StopTrackingDragGesture(bool aClearInChildProcesses) {
2473 mGestureDownContent = nullptr;
2474 mGestureDownFrameOwner = nullptr;
2475 mGestureDownInTextControl = false;
2476 mGestureDownDragStartData = nullptr;
2477
2478 // If a content process starts a drag but the mouse is released before the
2479 // parent starts the actual drag, the content process will think a drag is
2480 // still happening. Inform any child processes with active drags that the drag
2481 // should be stopped.
2482 if (!aClearInChildProcesses || !XRE_IsParentProcess()) {
2483 return;
2484 }
2485
2486 // Only notify if there is NOT a drag session active in the parent.
2487 RefPtr<nsIDragSession> dragSession =
2488 nsContentUtils::GetDragSession(mPresContext);
2489 if (dragSession) {
2490 return;
2491 }
2492 nsCOMPtr<nsIDragService> dragService =
2493 do_GetService("@mozilla.org/widget/dragservice;1");
2494 if (!dragService) {
2495 return;
2496 }
2497 dragService->RemoveAllBrowsers();
2498}
2499
2500void EventStateManager::FillInEventFromGestureDown(WidgetMouseEvent* aEvent) {
2501 NS_ASSERTION(aEvent->mWidget == mCurrentTarget->GetNearestWidget(),do { if (!(aEvent->mWidget == mCurrentTarget->GetNearestWidget
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Incorrect widget in event"
, "aEvent->mWidget == mCurrentTarget->GetNearestWidget()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2502); MOZ_PretendNoReturn(); } } while (0)
2502 "Incorrect widget in event")do { if (!(aEvent->mWidget == mCurrentTarget->GetNearestWidget
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Incorrect widget in event"
, "aEvent->mWidget == mCurrentTarget->GetNearestWidget()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2502); MOZ_PretendNoReturn(); } } while (0)
;
2503
2504 // Set the coordinates in the new event to the coordinates of
2505 // the old event, adjusted for the fact that the widget might be
2506 // different
2507 aEvent->mRefPoint =
2508 mGestureDownPoint - aEvent->mWidget->WidgetToScreenOffset();
2509 aEvent->mModifiers = mGestureModifiers;
2510 aEvent->mButtons = mGestureDownButtons;
2511 if (aEvent->mMessage == eContextMenu) {
2512 aEvent->mButton = mGestureDownButton;
2513 }
2514}
2515
2516void EventStateManager::MaybeFirePointerCancel(WidgetInputEvent* aEvent) {
2517 RefPtr<PresShell> presShell = mPresContext->GetPresShell();
2518 AutoWeakFrame targetFrame = mCurrentTarget;
2519
2520 if (!presShell || !targetFrame) {
2521 return;
2522 }
2523
2524 nsCOMPtr<nsIContent> content;
2525 targetFrame->GetContentForEvent(aEvent, getter_AddRefs(content));
2526 if (!content) {
2527 return;
2528 }
2529
2530 nsEventStatus status = nsEventStatus_eIgnore;
2531
2532 if (WidgetMouseEvent* aMouseEvent = aEvent->AsMouseEvent()) {
2533 WidgetPointerEvent event(*aMouseEvent);
2534 PointerEventHandler::InitPointerEventFromMouse(&event, aMouseEvent,
2535 ePointerCancel);
2536
2537 event.convertToPointer = false;
2538 presShell->HandleEventWithTarget(&event, targetFrame, content, &status);
2539 } else if (WidgetTouchEvent* aTouchEvent = aEvent->AsTouchEvent()) {
2540 WidgetPointerEvent event(aTouchEvent->IsTrusted(), ePointerCancel,
2541 aTouchEvent->mWidget);
2542
2543 PointerEventHandler::InitPointerEventFromTouch(event, *aTouchEvent,
2544 *aTouchEvent->mTouches[0]);
2545
2546 event.convertToPointer = false;
2547 presShell->HandleEventWithTarget(&event, targetFrame, content, &status);
2548 } else {
2549 MOZ_ASSERT(false)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2549); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ")")
; do { *((volatile int*)__null) = 2549; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2550 }
2551
2552 // HandleEventWithTarget clears out mCurrentTarget, which may be used in the
2553 // caller GenerateDragGesture. We have to restore mCurrentTarget.
2554 mCurrentTarget = targetFrame;
2555}
2556
2557bool EventStateManager::IsEventOutsideDragThreshold(
2558 WidgetInputEvent* aEvent) const {
2559 static int32_t sPixelThresholdX = 0;
2560 static int32_t sPixelThresholdY = 0;
2561
2562 if (!sPixelThresholdX) {
2563 sPixelThresholdX =
2564 LookAndFeel::GetInt(LookAndFeel::IntID::DragThresholdX, 0);
2565 sPixelThresholdY =
2566 LookAndFeel::GetInt(LookAndFeel::IntID::DragThresholdY, 0);
2567 if (sPixelThresholdX <= 0) {
2568 sPixelThresholdX = 5;
2569 }
2570 if (sPixelThresholdY <= 0) {
2571 sPixelThresholdY = 5;
2572 }
2573 }
2574
2575 LayoutDeviceIntPoint pt =
2576 aEvent->mWidget->WidgetToScreenOffset() + GetEventRefPoint(aEvent);
2577 LayoutDeviceIntPoint distance = pt - mGestureDownPoint;
2578 return Abs(distance.x) > sPixelThresholdX ||
2579 Abs(distance.y) > sPixelThresholdY;
2580}
2581
2582//
2583// GenerateDragGesture
2584//
2585// If we're in the TRACKING state of the d&d gesture tracker, check the current
2586// position of the mouse in relation to the old one. If we've moved a sufficient
2587// amount from the mouse down, then fire off a drag gesture event.
2588void EventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
2589 WidgetInputEvent* aEvent) {
2590 NS_ASSERTION(aPresContext, "This shouldn't happen.")do { if (!(aPresContext)) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"This shouldn't happen.", "aPresContext", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2590); MOZ_PretendNoReturn(); } } while (0)
;
2591 if (!IsTrackingDragGesture()) {
2592 return;
2593 }
2594
2595 AutoWeakFrame targetFrameBefore = mCurrentTarget;
2596 auto autoRestore = MakeScopeExit([&] { mCurrentTarget = targetFrameBefore; });
2597 mCurrentTarget = mGestureDownFrameOwner->GetPrimaryFrame();
2598
2599 if (!mCurrentTarget || !mCurrentTarget->GetNearestWidget()) {
2600 StopTrackingDragGesture(true);
2601 return;
2602 }
2603
2604 // Check if selection is tracking drag gestures, if so
2605 // don't interfere!
2606 if (mCurrentTarget) {
2607 RefPtr<nsFrameSelection> frameSel = mCurrentTarget->GetFrameSelection();
2608 if (frameSel && frameSel->GetDragState()) {
2609 StopTrackingDragGesture(true);
2610 return;
2611 }
2612 }
2613
2614 // If non-native code is capturing the mouse don't start a drag.
2615 if (PresShell::IsMouseCapturePreventingDrag()) {
2616 StopTrackingDragGesture(true);
2617 return;
2618 }
2619
2620 if (!IsEventOutsideDragThreshold(aEvent)) {
2621 // To keep the old behavior, flush layout even if we don't start dnd.
2622 FlushLayout(aPresContext);
2623 return;
2624 }
2625
2626 if (StaticPrefs::ui_click_hold_context_menus()) {
2627 // stop the click-hold before we fire off the drag gesture, in case
2628 // it takes a long time
2629 KillClickHoldTimer();
2630 }
2631
2632 nsCOMPtr<nsIDocShell> docshell = aPresContext->GetDocShell();
2633 if (!docshell) {
2634 return;
2635 }
2636
2637 nsCOMPtr<nsPIDOMWindowOuter> window = docshell->GetWindow();
2638 if (!window) return;
2639
2640 RefPtr<DataTransfer> dataTransfer =
2641 new DataTransfer(window, eDragStart, /* aIsExternal */ false,
2642 /* aClipboardType */ Nothing());
2643 auto protectDataTransfer = MakeScopeExit([&] {
2644 if (dataTransfer) {
2645 dataTransfer->Disconnect();
2646 }
2647 });
2648
2649 RefPtr<Selection> selection;
2650 RefPtr<RemoteDragStartData> remoteDragStartData;
2651 nsCOMPtr<nsIContent> eventContent, targetContent;
2652 nsCOMPtr<nsIPrincipal> principal;
2653 nsCOMPtr<nsIContentSecurityPolicy> csp;
2654 nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
2655 bool allowEmptyDataTransfer = false;
2656 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(eventContent));
2657 if (eventContent) {
2658 // If the content is a text node in a password field, we shouldn't
2659 // allow to drag its raw text. Note that we've supported drag from
2660 // password fields but dragging data was masked text. So, it doesn't
2661 // make sense anyway.
2662 if (eventContent->IsText() && eventContent->HasFlag(NS_MAYBE_MASKED)) {
2663 // However, it makes sense to allow to drag selected password text
2664 // when copying selected password is allowed because users may want
2665 // to use drag and drop rather than copy and paste when web apps
2666 // request to input password twice for conforming new password but
2667 // they used password generator.
2668 TextEditor* textEditor =
2669 nsContentUtils::GetTextEditorFromAnonymousNodeWithoutCreation(
2670 eventContent);
2671 if (!textEditor || !textEditor->IsCopyToClipboardAllowed()) {
2672 StopTrackingDragGesture(true);
2673 return;
2674 }
2675 }
2676 DetermineDragTargetAndDefaultData(
2677 window, eventContent, dataTransfer, &allowEmptyDataTransfer,
2678 getter_AddRefs(selection), getter_AddRefs(remoteDragStartData),
2679 getter_AddRefs(targetContent), getter_AddRefs(principal),
2680 getter_AddRefs(csp), getter_AddRefs(cookieJarSettings));
2681 }
2682
2683 // Stop tracking the drag gesture now. This should stop us from
2684 // reentering GenerateDragGesture inside DOM event processing.
2685 // Pass false to avoid clearing the child process state since a real
2686 // drag should be starting.
2687 StopTrackingDragGesture(false);
2688
2689 if (!targetContent) return;
2690
2691 // Use our targetContent, now that we've determined it, as the
2692 // parent object of the DataTransfer.
2693 nsCOMPtr<nsIContent> parentContent =
2694 targetContent->FindFirstNonChromeOnlyAccessContent();
2695 dataTransfer->SetParentObject(parentContent);
2696
2697 sLastDragOverFrame = nullptr;
2698 nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget();
2699
2700 // get the widget from the target frame
2701 WidgetDragEvent startEvent(aEvent->IsTrusted(), eDragStart, widget);
2702 startEvent.mFlags.mIsSynthesizedForTests =
2703 aEvent->mFlags.mIsSynthesizedForTests;
2704 FillInEventFromGestureDown(&startEvent);
2705
2706 startEvent.mDataTransfer = dataTransfer;
2707 if (aEvent->AsMouseEvent()) {
2708 startEvent.mInputSource = aEvent->AsMouseEvent()->mInputSource;
2709 } else if (aEvent->AsTouchEvent()) {
2710 startEvent.mInputSource = MouseEvent_Binding::MOZ_SOURCE_TOUCH;
2711 } else {
2712 MOZ_ASSERT(false)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2712); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ")")
; do { *((volatile int*)__null) = 2712; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2713 }
2714
2715 // Dispatch to the DOM. By setting mCurrentTarget we are faking
2716 // out the ESM and telling it that the current target frame is
2717 // actually where the mouseDown occurred, otherwise it will use
2718 // the frame the mouse is currently over which may or may not be
2719 // the same.
2720
2721 // Hold onto old target content through the event and reset after.
2722 nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
2723
2724 // Set the current target to the content for the mouse down
2725 mCurrentTargetContent = targetContent;
2726
2727 // Dispatch the dragstart event to the DOM.
2728 nsEventStatus status = nsEventStatus_eIgnore;
2729 EventDispatcher::Dispatch(targetContent, aPresContext, &startEvent, nullptr,
2730 &status);
2731
2732 WidgetDragEvent* event = &startEvent;
2733
2734 nsCOMPtr<nsIObserverService> observerService =
2735 mozilla::services::GetObserverService();
2736 // Emit observer event to allow addons to modify the DataTransfer
2737 // object.
2738 if (observerService) {
2739 observerService->NotifyObservers(dataTransfer, "on-datatransfer-available",
2740 nullptr);
2741 }
2742
2743 if (status != nsEventStatus_eConsumeNoDefault) {
2744 bool dragStarted = DoDefaultDragStart(aPresContext, event, dataTransfer,
2745 allowEmptyDataTransfer, targetContent,
2746 selection, remoteDragStartData,
2747 principal, csp, cookieJarSettings);
2748 if (dragStarted) {
2749 sActiveESM = nullptr;
2750 MaybeFirePointerCancel(aEvent);
2751 aEvent->StopPropagation();
2752 }
2753 }
2754
2755 // Reset mCurretTargetContent to what it was
2756 mCurrentTargetContent = targetBeforeEvent;
2757
2758 // Now flush all pending notifications, for better responsiveness
2759 // while dragging.
2760 FlushLayout(aPresContext);
2761} // GenerateDragGesture
2762
2763void EventStateManager::DetermineDragTargetAndDefaultData(
2764 nsPIDOMWindowOuter* aWindow, nsIContent* aSelectionTarget,
2765 DataTransfer* aDataTransfer, bool* aAllowEmptyDataTransfer,
2766 Selection** aSelection, RemoteDragStartData** aRemoteDragStartData,
2767 nsIContent** aTargetNode, nsIPrincipal** aPrincipal,
2768 nsIContentSecurityPolicy** aCsp,
2769 nsICookieJarSettings** aCookieJarSettings) {
2770 *aTargetNode = nullptr;
2771 *aAllowEmptyDataTransfer = false;
2772 nsCOMPtr<nsIContent> dragDataNode;
2773
2774 nsIContent* editingElement = aSelectionTarget->IsEditable()
2775 ? aSelectionTarget->GetEditingHost()
2776 : nullptr;
2777
2778 // In chrome, only allow dragging inside editable areas.
2779 bool isChromeContext = !aWindow->GetBrowsingContext()->IsContent();
2780 if (isChromeContext && !editingElement) {
2781 if (mGestureDownDragStartData) {
2782 // A child process started a drag so use any data it assigned for the dnd
2783 // session.
2784 mGestureDownDragStartData->AddInitialDnDDataTo(aDataTransfer, aPrincipal,
2785 aCsp, aCookieJarSettings);
2786 mGestureDownDragStartData.forget(aRemoteDragStartData);
2787 *aAllowEmptyDataTransfer = true;
2788 }
2789 } else {
2790 mGestureDownDragStartData = nullptr;
2791
2792 // GetDragData determines if a selection, link or image in the content
2793 // should be dragged, and places the data associated with the drag in the
2794 // data transfer.
2795 // mGestureDownContent is the node where the mousedown event for the drag
2796 // occurred, and aSelectionTarget is the node to use when a selection is
2797 // used
2798 bool canDrag;
2799 bool wasAlt = (mGestureModifiers & MODIFIER_ALT) != 0;
2800 nsresult rv = nsContentAreaDragDrop::GetDragData(
2801 aWindow, mGestureDownContent, aSelectionTarget, wasAlt, aDataTransfer,
2802 &canDrag, aSelection, getter_AddRefs(dragDataNode), aCsp,
2803 aCookieJarSettings);
2804 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !canDrag) {
2805 return;
2806 }
2807 }
2808
2809 // if GetDragData returned a node, use that as the node being dragged.
2810 // Otherwise, if a selection is being dragged, use the node within the
2811 // selection that was dragged. Otherwise, just use the mousedown target.
2812 nsIContent* dragContent = mGestureDownContent;
2813 if (dragDataNode)
2814 dragContent = dragDataNode;
2815 else if (*aSelection)
2816 dragContent = aSelectionTarget;
2817
2818 nsIContent* originalDragContent = dragContent;
2819
2820 // If a selection isn't being dragged, look for an ancestor with the
2821 // draggable property set. If one is found, use that as the target of the
2822 // drag instead of the node that was clicked on. If a draggable node wasn't
2823 // found, just use the clicked node.
2824 if (!*aSelection) {
2825 while (dragContent) {
2826 if (auto htmlElement = nsGenericHTMLElement::FromNode(dragContent)) {
2827 if (htmlElement->Draggable()) {
2828 // We let draggable elements to trigger dnd even if there is no data
2829 // in the DataTransfer.
2830 *aAllowEmptyDataTransfer = true;
2831 break;
2832 }
2833 } else {
2834 if (dragContent->IsXULElement()) {
2835 // All XUL elements are draggable, so if a XUL element is
2836 // encountered, stop looking for draggable nodes and just use the
2837 // original clicked node instead.
2838 // XXXndeakin
2839 // In the future, we will want to improve this so that XUL has a
2840 // better way to specify whether something is draggable than just
2841 // on/off.
2842 dragContent = mGestureDownContent;
2843 break;
2844 }
2845 // otherwise, it's not an HTML or XUL element, so just keep looking
2846 }
2847 dragContent = dragContent->GetFlattenedTreeParent();
2848 }
2849 }
2850
2851 // if no node in the hierarchy was found to drag, but the GetDragData method
2852 // returned a node, use that returned node. Otherwise, nothing is draggable.
2853 if (!dragContent && dragDataNode) dragContent = dragDataNode;
2854
2855 if (dragContent) {
2856 // if an ancestor node was used instead, clear the drag data
2857 // XXXndeakin rework this a bit. Find a way to just not call GetDragData if
2858 // we don't need to.
2859 if (dragContent != originalDragContent) aDataTransfer->ClearAll();
2860 *aTargetNode = dragContent;
2861 NS_ADDREF(*aTargetNode)(*aTargetNode)->AddRef();
2862 }
2863}
2864
2865bool EventStateManager::DoDefaultDragStart(
2866 nsPresContext* aPresContext, WidgetDragEvent* aDragEvent,
2867 DataTransfer* aDataTransfer, bool aAllowEmptyDataTransfer,
2868 nsIContent* aDragTarget, Selection* aSelection,
2869 RemoteDragStartData* aDragStartData, nsIPrincipal* aPrincipal,
2870 nsIContentSecurityPolicy* aCsp, nsICookieJarSettings* aCookieJarSettings) {
2871 nsCOMPtr<nsIDragService> dragService =
2872 do_GetService("@mozilla.org/widget/dragservice;1");
2873 if (!dragService) return false;
2874
2875 // Default handling for the dragstart event.
2876 //
2877 // First, check if a drag session already exists. This means that the drag
2878 // service was called directly within a draggesture handler. In this case,
2879 // don't do anything more, as it is assumed that the handler is managing
2880 // drag and drop manually. Make sure to return true to indicate that a drag
2881 // began. However, if we're handling drag session for synthesized events,
2882 // we need to initialize some information of the session. Therefore, we
2883 // need to keep going for synthesized case.
2884 if (MOZ_UNLIKELY(!mPresContext)(__builtin_expect(!!(!mPresContext), 0))) {
2885 return true;
2886 }
2887 nsCOMPtr<nsIDragSession> dragSession =
2888 dragService->GetCurrentSession(mPresContext->GetRootWidget());
2889 if (dragSession && !dragSession->IsSynthesizedForTests()) {
2890 return true;
2891 }
2892
2893 // No drag session is currently active, so check if a handler added
2894 // any items to be dragged. If not, there isn't anything to drag.
2895 uint32_t count = 0;
2896 if (aDataTransfer) {
2897 count = aDataTransfer->MozItemCount();
2898 }
2899 if (!aAllowEmptyDataTransfer && !count) {
2900 return false;
2901 }
2902
2903 // Get the target being dragged, which may not be the same as the
2904 // target of the mouse event. If one wasn't set in the
2905 // aDataTransfer during the event handler, just use the original
2906 // target instead.
2907 nsCOMPtr<nsIContent> dragTarget = aDataTransfer->GetDragTarget();
2908 if (!dragTarget) {
2909 dragTarget = aDragTarget;
2910 if (!dragTarget) {
2911 return false;
2912 }
2913 }
2914
2915 // check which drag effect should initially be used. If the effect was not
2916 // set, just use all actions, otherwise Windows won't allow a drop.
2917 uint32_t action = aDataTransfer->EffectAllowedInt();
2918 if (action == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED) {
2919 action = nsIDragService::DRAGDROP_ACTION_COPY |
2920 nsIDragService::DRAGDROP_ACTION_MOVE |
2921 nsIDragService::DRAGDROP_ACTION_LINK;
2922 }
2923
2924 // get any custom drag image that was set
2925 int32_t imageX, imageY;
2926 RefPtr<Element> dragImage = aDataTransfer->GetDragImage(&imageX, &imageY);
2927
2928 nsCOMPtr<nsIArray> transArray = aDataTransfer->GetTransferables(dragTarget);
2929 if (!transArray) {
2930 return false;
2931 }
2932
2933 RefPtr<DataTransfer> dataTransfer;
2934 if (!dragSession) {
2935 // After this function returns, the DataTransfer will be cleared so it
2936 // appears empty to content. We need to pass a DataTransfer into the Drag
2937 // Session, so we need to make a copy.
2938 aDataTransfer->Clone(aDragTarget, eDrop, aDataTransfer->MozUserCancelled(),
2939 false, getter_AddRefs(dataTransfer));
2940
2941 // Copy over the drop effect, as Clone doesn't copy it for us.
2942 dataTransfer->SetDropEffectInt(aDataTransfer->DropEffectInt());
2943 } else {
2944 MOZ_ASSERT(dragSession->IsSynthesizedForTests())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(dragSession->IsSynthesizedForTests())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(dragSession->IsSynthesizedForTests()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("dragSession->IsSynthesizedForTests()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2944); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dragSession->IsSynthesizedForTests()"
")"); do { *((volatile int*)__null) = 2944; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2945 MOZ_ASSERT(aDragEvent->mFlags.mIsSynthesizedForTests)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDragEvent->mFlags.mIsSynthesizedForTests)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aDragEvent->mFlags.mIsSynthesizedForTests))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aDragEvent->mFlags.mIsSynthesizedForTests"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2945); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDragEvent->mFlags.mIsSynthesizedForTests"
")"); do { *((volatile int*)__null) = 2945; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2946 // If we're initializing synthesized drag session, we should use given
2947 // DataTransfer as is because it'll be used with following drag events
2948 // in any tests, therefore it should be set to nsIDragSession.dataTransfer
2949 // because it and DragEvent.dataTransfer should be same instance.
2950 dataTransfer = aDataTransfer;
2951 }
2952
2953 // XXXndeakin don't really want to create a new drag DOM event
2954 // here, but we need something to pass to the InvokeDragSession
2955 // methods.
2956 RefPtr<DragEvent> event =
2957 NS_NewDOMDragEvent(dragTarget, aPresContext, aDragEvent);
2958
2959 // Use InvokeDragSessionWithSelection if a selection is being dragged,
2960 // such that the image can be generated from the selected text. However,
2961 // use InvokeDragSessionWithImage if a custom image was set or something
2962 // other than a selection is being dragged.
2963 if (!dragImage && aSelection) {
2964 dragService->InvokeDragSessionWithSelection(
2965 aSelection, aPrincipal, aCsp, aCookieJarSettings, transArray, action,
2966 event, dataTransfer, dragTarget);
2967 } else if (aDragStartData) {
2968 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 2968); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 2968; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2969 dragService->InvokeDragSessionWithRemoteImage(
2970 dragTarget, aPrincipal, aCsp, aCookieJarSettings, transArray, action,
2971 aDragStartData, event, dataTransfer);
2972 } else {
2973 dragService->InvokeDragSessionWithImage(
2974 dragTarget, aPrincipal, aCsp, aCookieJarSettings, transArray, action,
2975 dragImage, imageX, imageY, event, dataTransfer);
2976 }
2977
2978 return true;
2979}
2980
2981void EventStateManager::ChangeZoom(bool aIncrease) {
2982 // Send the zoom change to the top level browser so it will be handled by the
2983 // front end in the same way as other zoom actions.
2984 nsIDocShell* docShell = mDocument->GetDocShell();
2985 if (!docShell) {
2986 return;
2987 }
2988
2989 BrowsingContext* bc = docShell->GetBrowsingContext();
2990 if (!bc) {
2991 return;
2992 }
2993
2994 if (XRE_IsParentProcess()) {
2995 bc->Canonical()->DispatchWheelZoomChange(aIncrease);
2996 } else if (BrowserChild* child = BrowserChild::GetFrom(docShell)) {
2997 child->SendWheelZoomChange(aIncrease);
2998 }
2999}
3000
3001void EventStateManager::DoScrollHistory(int32_t direction) {
3002 nsCOMPtr<nsISupports> pcContainer(mPresContext->GetContainerWeak());
3003 if (pcContainer) {
3004 nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(pcContainer));
3005 if (webNav) {
3006 // positive direction to go back one step, nonpositive to go forward
3007 // This is doing user-initiated history traversal, hence we want
3008 // to require that history entries we navigate to have user interaction.
3009 if (direction > 0)
3010 webNav->GoBack(StaticPrefs::browser_navigation_requireUserInteraction(),
3011 true);
3012 else
3013 webNav->GoForward(
3014 StaticPrefs::browser_navigation_requireUserInteraction(), true);
3015 }
3016 }
3017}
3018
3019void EventStateManager::DoScrollZoom(nsIFrame* aTargetFrame,
3020 int32_t adjustment) {
3021 // Exclude content in chrome docshells.
3022 nsIContent* content = aTargetFrame->GetContent();
3023 if (content && !nsContentUtils::IsInChromeDocshell(content->OwnerDoc())) {
3024 // Positive adjustment to decrease zoom, negative to increase
3025 const bool increase = adjustment <= 0;
3026 EnsureDocument(mPresContext);
3027 ChangeZoom(increase);
3028 }
3029}
3030
3031static nsIFrame* GetParentFrameToScroll(nsIFrame* aFrame) {
3032 if (!aFrame) return nullptr;
3033
3034 if (aFrame->StyleDisplay()->mPosition == StylePositionProperty::Fixed &&
3035 nsLayoutUtils::IsReallyFixedPos(aFrame)) {
3036 return aFrame->PresShell()->GetRootScrollContainerFrame();
3037 }
3038 return aFrame->GetParent();
3039}
3040
3041void EventStateManager::DispatchLegacyMouseScrollEvents(
3042 nsIFrame* aTargetFrame, WidgetWheelEvent* aEvent, nsEventStatus* aStatus) {
3043 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3043); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 3043; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3044 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3044); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 3044; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3045
3046 if (!aTargetFrame || *aStatus == nsEventStatus_eConsumeNoDefault) {
3047 return;
3048 }
3049
3050 // Ignore mouse wheel transaction for computing legacy mouse wheel
3051 // events' delta value.
3052 // DOM event's delta vales are computed from CSS pixels.
3053 auto scrollAmountInCSSPixels =
3054 CSSIntSize::FromAppUnitsRounded(aEvent->mScrollAmount);
3055
3056 // XXX We don't deal with fractional amount in legacy event, though the
3057 // default action handler (DoScrollText()) deals with it.
3058 // If we implemented such strict computation, we would need additional
3059 // accumulated delta values. It would made the code more complicated.
3060 // And also it would computes different delta values from older version.
3061 // It doesn't make sense to implement such code for legacy events and
3062 // rare cases.
3063 int32_t scrollDeltaX, scrollDeltaY, pixelDeltaX, pixelDeltaY;
3064 switch (aEvent->mDeltaMode) {
3065 case WheelEvent_Binding::DOM_DELTA_PAGE:
3066 scrollDeltaX = !aEvent->mLineOrPageDeltaX
3067 ? 0
3068 : (aEvent->mLineOrPageDeltaX > 0
3069 ? UIEvent_Binding::SCROLL_PAGE_DOWN
3070 : UIEvent_Binding::SCROLL_PAGE_UP);
3071 scrollDeltaY = !aEvent->mLineOrPageDeltaY
3072 ? 0
3073 : (aEvent->mLineOrPageDeltaY > 0
3074 ? UIEvent_Binding::SCROLL_PAGE_DOWN
3075 : UIEvent_Binding::SCROLL_PAGE_UP);
3076 pixelDeltaX = RoundDown(aEvent->mDeltaX * scrollAmountInCSSPixels.width);
3077 pixelDeltaY = RoundDown(aEvent->mDeltaY * scrollAmountInCSSPixels.height);
3078 break;
3079
3080 case WheelEvent_Binding::DOM_DELTA_LINE:
3081 scrollDeltaX = aEvent->mLineOrPageDeltaX;
3082 scrollDeltaY = aEvent->mLineOrPageDeltaY;
3083 pixelDeltaX = RoundDown(aEvent->mDeltaX * scrollAmountInCSSPixels.width);
3084 pixelDeltaY = RoundDown(aEvent->mDeltaY * scrollAmountInCSSPixels.height);
3085 break;
3086
3087 case WheelEvent_Binding::DOM_DELTA_PIXEL:
3088 scrollDeltaX = aEvent->mLineOrPageDeltaX;
3089 scrollDeltaY = aEvent->mLineOrPageDeltaY;
3090 pixelDeltaX = RoundDown(aEvent->mDeltaX);
3091 pixelDeltaY = RoundDown(aEvent->mDeltaY);
3092 break;
3093
3094 default:
3095 MOZ_CRASH("Invalid deltaMode value comes")do { do { } while (false); MOZ_ReportCrash("" "Invalid deltaMode value comes"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3095); AnnotateMozCrashReason("MOZ_CRASH(" "Invalid deltaMode value comes"
")"); do { *((volatile int*)__null) = 3095; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
3096 }
3097
3098 // Send the legacy events in following order:
3099 // 1. Vertical scroll
3100 // 2. Vertical pixel scroll (even if #1 isn't consumed)
3101 // 3. Horizontal scroll (even if #1 and/or #2 are consumed)
3102 // 4. Horizontal pixel scroll (even if #3 isn't consumed)
3103
3104 AutoWeakFrame targetFrame(aTargetFrame);
3105
3106 MOZ_ASSERT(*aStatus != nsEventStatus_eConsumeNoDefault &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault &&
!aEvent->DefaultPrevented())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aStatus != nsEventStatus_eConsumeNoDefault
&& !aEvent->DefaultPrevented()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
" (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3109); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
") (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")"); do {
*((volatile int*)__null) = 3109; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3107 !aEvent->DefaultPrevented(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault &&
!aEvent->DefaultPrevented())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aStatus != nsEventStatus_eConsumeNoDefault
&& !aEvent->DefaultPrevented()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
" (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3109); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
") (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")"); do {
*((volatile int*)__null) = 3109; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3108 "If you make legacy events dispatched for default prevented wheel "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault &&
!aEvent->DefaultPrevented())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aStatus != nsEventStatus_eConsumeNoDefault
&& !aEvent->DefaultPrevented()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
" (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3109); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
") (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")"); do {
*((volatile int*)__null) = 3109; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3109 "event, you need to initialize stateX and stateY")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault &&
!aEvent->DefaultPrevented())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aStatus != nsEventStatus_eConsumeNoDefault
&& !aEvent->DefaultPrevented()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
" (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3109); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault && !aEvent->DefaultPrevented()"
") (" "If you make legacy events dispatched for default prevented wheel "
"event, you need to initialize stateX and stateY" ")"); do {
*((volatile int*)__null) = 3109; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
3110 EventState stateX, stateY;
3111 if (scrollDeltaY) {
3112 SendLineScrollEvent(aTargetFrame, aEvent, stateY, scrollDeltaY,
3113 DELTA_DIRECTION_Y);
3114 if (!targetFrame.IsAlive()) {
3115 *aStatus = nsEventStatus_eConsumeNoDefault;
3116 return;
3117 }
3118 }
3119
3120 if (pixelDeltaY) {
3121 SendPixelScrollEvent(aTargetFrame, aEvent, stateY, pixelDeltaY,
3122 DELTA_DIRECTION_Y);
3123 if (!targetFrame.IsAlive()) {
3124 *aStatus = nsEventStatus_eConsumeNoDefault;
3125 return;
3126 }
3127 }
3128
3129 if (scrollDeltaX) {
3130 SendLineScrollEvent(aTargetFrame, aEvent, stateX, scrollDeltaX,
3131 DELTA_DIRECTION_X);
3132 if (!targetFrame.IsAlive()) {
3133 *aStatus = nsEventStatus_eConsumeNoDefault;
3134 return;
3135 }
3136 }
3137
3138 if (pixelDeltaX) {
3139 SendPixelScrollEvent(aTargetFrame, aEvent, stateX, pixelDeltaX,
3140 DELTA_DIRECTION_X);
3141 if (!targetFrame.IsAlive()) {
3142 *aStatus = nsEventStatus_eConsumeNoDefault;
3143 return;
3144 }
3145 }
3146
3147 if (stateY.mDefaultPrevented) {
3148 *aStatus = nsEventStatus_eConsumeNoDefault;
3149 aEvent->PreventDefault(!stateY.mDefaultPreventedByContent);
3150 }
3151
3152 if (stateX.mDefaultPrevented) {
3153 *aStatus = nsEventStatus_eConsumeNoDefault;
3154 aEvent->PreventDefault(!stateX.mDefaultPreventedByContent);
3155 }
3156}
3157
3158void EventStateManager::SendLineScrollEvent(nsIFrame* aTargetFrame,
3159 WidgetWheelEvent* aEvent,
3160 EventState& aState, int32_t aDelta,
3161 DeltaDirection aDeltaDirection) {
3162 nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
3163 if (!targetContent) {
3164 targetContent = GetFocusedElement();
3165 if (!targetContent) {
3166 return;
3167 }
3168 }
3169
3170 while (targetContent->IsText()) {
3171 targetContent = targetContent->GetFlattenedTreeParent();
3172 }
3173
3174 WidgetMouseScrollEvent event(aEvent->IsTrusted(),
3175 eLegacyMouseLineOrPageScroll, aEvent->mWidget);
3176 event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
3177 event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
3178 event.mRefPoint = aEvent->mRefPoint;
3179 event.mTimeStamp = aEvent->mTimeStamp;
3180 event.mModifiers = aEvent->mModifiers;
3181 event.mButtons = aEvent->mButtons;
3182 event.mIsHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
3183 event.mDelta = aDelta;
3184 event.mInputSource = aEvent->mInputSource;
3185
3186 RefPtr<nsPresContext> presContext = aTargetFrame->PresContext();
3187 nsEventStatus status = nsEventStatus_eIgnore;
3188 EventDispatcher::Dispatch(targetContent, presContext, &event, nullptr,
3189 &status);
3190 aState.mDefaultPrevented =
3191 event.DefaultPrevented() || status == nsEventStatus_eConsumeNoDefault;
3192 aState.mDefaultPreventedByContent = event.DefaultPreventedByContent();
3193}
3194
3195void EventStateManager::SendPixelScrollEvent(nsIFrame* aTargetFrame,
3196 WidgetWheelEvent* aEvent,
3197 EventState& aState,
3198 int32_t aPixelDelta,
3199 DeltaDirection aDeltaDirection) {
3200 nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
3201 if (!targetContent) {
3202 targetContent = GetFocusedElement();
3203 if (!targetContent) {
3204 return;
3205 }
3206 }
3207
3208 while (targetContent->IsText()) {
3209 targetContent = targetContent->GetFlattenedTreeParent();
3210 }
3211
3212 WidgetMouseScrollEvent event(aEvent->IsTrusted(), eLegacyMousePixelScroll,
3213 aEvent->mWidget);
3214 event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
3215 event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
3216 event.mRefPoint = aEvent->mRefPoint;
3217 event.mTimeStamp = aEvent->mTimeStamp;
3218 event.mModifiers = aEvent->mModifiers;
3219 event.mButtons = aEvent->mButtons;
3220 event.mIsHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
3221 event.mDelta = aPixelDelta;
3222 event.mInputSource = aEvent->mInputSource;
3223
3224 RefPtr<nsPresContext> presContext = aTargetFrame->PresContext();
3225 nsEventStatus status = nsEventStatus_eIgnore;
3226 EventDispatcher::Dispatch(targetContent, presContext, &event, nullptr,
3227 &status);
3228 aState.mDefaultPrevented =
3229 event.DefaultPrevented() || status == nsEventStatus_eConsumeNoDefault;
3230 aState.mDefaultPreventedByContent = event.DefaultPreventedByContent();
3231}
3232
3233ScrollContainerFrame*
3234EventStateManager::ComputeScrollTargetAndMayAdjustWheelEvent(
3235 nsIFrame* aTargetFrame, WidgetWheelEvent* aEvent,
3236 ComputeScrollTargetOptions aOptions) {
3237 return ComputeScrollTargetAndMayAdjustWheelEvent(
3238 aTargetFrame, aEvent->mDeltaX, aEvent->mDeltaY, aEvent, aOptions);
3239}
3240
3241// Overload ComputeScrollTargetAndMayAdjustWheelEvent method to allow passing
3242// "test" dx and dy when looking for which scrollbarmediators to activate when
3243// two finger down on trackpad and before any actual motion
3244ScrollContainerFrame*
3245EventStateManager::ComputeScrollTargetAndMayAdjustWheelEvent(
3246 nsIFrame* aTargetFrame, double aDirectionX, double aDirectionY,
3247 WidgetWheelEvent* aEvent, ComputeScrollTargetOptions aOptions) {
3248 bool isAutoDir = false;
3249 bool honoursRoot = false;
3250 if (MAY_BE_ADJUSTED_BY_AUTO_DIR & aOptions) {
3251 // If the scroll is respected as auto-dir, aDirection* should always be
3252 // equivalent to the event's delta vlaues(Currently, there are only one case
3253 // where aDirection*s have different values from the widget wheel event's
3254 // original delta values and the only case isn't auto-dir, see
3255 // ScrollbarsForWheel::TemporarilyActivateAllPossibleScrollTargets).
3256 MOZ_ASSERT(aDirectionX == aEvent->mDeltaX &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDirectionX == aEvent->mDeltaX && aDirectionY
== aEvent->mDeltaY)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDirectionX == aEvent->mDeltaX
&& aDirectionY == aEvent->mDeltaY))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aDirectionX == aEvent->mDeltaX && aDirectionY == aEvent->mDeltaY"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3257); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDirectionX == aEvent->mDeltaX && aDirectionY == aEvent->mDeltaY"
")"); do { *((volatile int*)__null) = 3257; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3257 aDirectionY == aEvent->mDeltaY)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDirectionX == aEvent->mDeltaX && aDirectionY
== aEvent->mDeltaY)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDirectionX == aEvent->mDeltaX
&& aDirectionY == aEvent->mDeltaY))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aDirectionX == aEvent->mDeltaX && aDirectionY == aEvent->mDeltaY"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3257); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDirectionX == aEvent->mDeltaX && aDirectionY == aEvent->mDeltaY"
")"); do { *((volatile int*)__null) = 3257; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3258
3259 WheelDeltaAdjustmentStrategy strategy =
3260 GetWheelDeltaAdjustmentStrategy(*aEvent);
3261 switch (strategy) {
3262 case WheelDeltaAdjustmentStrategy::eAutoDir:
3263 isAutoDir = true;
3264 honoursRoot = false;
3265 break;
3266 case WheelDeltaAdjustmentStrategy::eAutoDirWithRootHonour:
3267 isAutoDir = true;
3268 honoursRoot = true;
3269 break;
3270 default:
3271 break;
3272 }
3273 }
3274
3275 if (aOptions & PREFER_MOUSE_WHEEL_TRANSACTION) {
3276 // If the user recently scrolled with the mousewheel, then they probably
3277 // want to scroll the same view as before instead of the view under the
3278 // cursor. WheelTransaction tracks the frame currently being
3279 // scrolled with the mousewheel. We consider the transaction ended when the
3280 // mouse moves more than "mousewheel.transaction.ignoremovedelay"
3281 // milliseconds after the last scroll operation, or any time the mouse moves
3282 // out of the frame, or when more than "mousewheel.transaction.timeout"
3283 // milliseconds have passed after the last operation, even if the mouse
3284 // hasn't moved.
3285 nsIFrame* lastScrollFrame = WheelTransaction::GetScrollTargetFrame();
3286 if (lastScrollFrame) {
3287 ScrollContainerFrame* scrollContainerFrame =
3288 lastScrollFrame->GetScrollTargetFrame();
3289 if (scrollContainerFrame) {
3290 if (isAutoDir) {
3291 ESMAutoDirWheelDeltaAdjuster adjuster(*aEvent, *lastScrollFrame,
3292 honoursRoot);
3293 // Note that calling this function will not always cause the delta to
3294 // be adjusted, it only adjusts the delta when it should, because
3295 // Adjust() internally calls ShouldBeAdjusted() before making
3296 // adjustment.
3297 adjuster.Adjust();
3298 }
3299 return scrollContainerFrame;
3300 }
3301 }
3302 }
3303
3304 // If the event doesn't cause scroll actually, we cannot find scroll target
3305 // because we check if the event can cause scroll actually on each found
3306 // scrollable frame.
3307 if (!aDirectionX && !aDirectionY) {
3308 return nullptr;
3309 }
3310
3311 bool checkIfScrollableX;
3312 bool checkIfScrollableY;
3313 if (isAutoDir) {
3314 // Always check the frame's scrollability in both the two directions for an
3315 // auto-dir scroll. That is, for an auto-dir scroll,
3316 // PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS and
3317 // PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS should be ignored.
3318 checkIfScrollableX = true;
3319 checkIfScrollableY = true;
3320 } else {
3321 checkIfScrollableX =
3322 aDirectionX &&
3323 (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS);
3324 checkIfScrollableY =
3325 aDirectionY &&
3326 (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS);
3327 }
3328
3329 nsIFrame* scrollFrame = !(aOptions & START_FROM_PARENT)
3330 ? aTargetFrame
3331 : GetParentFrameToScroll(aTargetFrame);
3332 for (; scrollFrame; scrollFrame = GetParentFrameToScroll(scrollFrame)) {
3333 // Check whether the frame wants to provide us with a scrollable view.
3334 ScrollContainerFrame* scrollContainerFrame =
3335 scrollFrame->GetScrollTargetFrame();
3336 if (!scrollContainerFrame) {
3337 nsMenuPopupFrame* menuPopupFrame = do_QueryFrame(scrollFrame);
3338 if (menuPopupFrame) {
3339 return nullptr;
3340 }
3341 continue;
3342 }
3343
3344 if (!checkIfScrollableX && !checkIfScrollableY) {
3345 return scrollContainerFrame;
3346 }
3347
3348 // If the frame disregards the direction the user is trying to scroll, then
3349 // it should just bubbles the scroll event up to its parental scroll frame
3350
3351 Maybe<layers::ScrollDirection> disregardedDirection =
3352 WheelHandlingUtils::GetDisregardedWheelScrollDirection(scrollFrame);
3353 if (disregardedDirection) {
3354 switch (disregardedDirection.ref()) {
3355 case layers::ScrollDirection::eHorizontal:
3356 if (checkIfScrollableX) {
3357 continue;
3358 }
3359 break;
3360 case layers::ScrollDirection::eVertical:
3361 if (checkIfScrollableY) {
3362 continue;
3363 }
3364 break;
3365 }
3366 }
3367
3368 layers::ScrollDirections directions =
3369 scrollContainerFrame
3370 ->GetAvailableScrollingDirectionsForUserInputEvents();
3371 if ((!(directions.contains(layers::ScrollDirection::eVertical)) &&
3372 !(directions.contains(layers::ScrollDirection::eHorizontal))) ||
3373 (checkIfScrollableY && !checkIfScrollableX &&
3374 !(directions.contains(layers::ScrollDirection::eVertical))) ||
3375 (checkIfScrollableX && !checkIfScrollableY &&
3376 !(directions.contains(layers::ScrollDirection::eHorizontal)))) {
3377 continue;
3378 }
3379
3380 // Computes whether the currently checked frame is scrollable by this wheel
3381 // event.
3382 bool canScroll = false;
3383 if (isAutoDir) {
3384 ESMAutoDirWheelDeltaAdjuster adjuster(*aEvent, *scrollFrame, honoursRoot);
3385 if (adjuster.ShouldBeAdjusted()) {
3386 adjuster.Adjust();
3387 canScroll = true;
3388 } else if (WheelHandlingUtils::CanScrollOn(scrollContainerFrame,
3389 aDirectionX, aDirectionY)) {
3390 canScroll = true;
3391 }
3392 } else if (WheelHandlingUtils::CanScrollOn(scrollContainerFrame,
3393 aDirectionX, aDirectionY)) {
3394 canScroll = true;
3395 }
3396
3397 if (canScroll) {
3398 return scrollContainerFrame;
3399 }
3400
3401 // Where we are at is the block ending in a for loop.
3402 // The current frame has been checked to be unscrollable by this wheel
3403 // event, continue the loop to check its parent, if any.
3404 }
3405
3406 nsIFrame* newFrame = nsLayoutUtils::GetCrossDocParentFrameInProcess(
3407 aTargetFrame->PresShell()->GetRootFrame());
3408 aOptions =
3409 static_cast<ComputeScrollTargetOptions>(aOptions & ~START_FROM_PARENT);
3410 if (!newFrame) {
3411 return nullptr;
3412 }
3413 return ComputeScrollTargetAndMayAdjustWheelEvent(newFrame, aEvent, aOptions);
3414}
3415
3416nsSize EventStateManager::GetScrollAmount(
3417 nsPresContext* aPresContext, WidgetWheelEvent* aEvent,
3418 ScrollContainerFrame* aScrollContainerFrame) {
3419 MOZ_ASSERT(aPresContext)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresContext))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPresContext", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3419); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresContext"
")"); do { *((volatile int*)__null) = 3419; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3420 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3420); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 3420; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3421
3422 const bool isPage = aEvent->mDeltaMode == WheelEvent_Binding::DOM_DELTA_PAGE;
3423 if (!aScrollContainerFrame) {
3424 // If there is no scrollable frame, we should use root, see below.
3425 aScrollContainerFrame =
3426 aPresContext->PresShell()->GetRootScrollContainerFrame();
3427 }
3428
3429 if (aScrollContainerFrame) {
3430 return isPage ? aScrollContainerFrame->GetPageScrollAmount()
3431 : aScrollContainerFrame->GetLineScrollAmount();
3432 }
3433
3434 // If there is no scrollable frame and page scrolling, use viewport size.
3435 if (isPage) {
3436 return aPresContext->GetVisibleArea().Size();
3437 }
3438
3439 // Otherwise use root frame's font metrics.
3440 //
3441 // FIXME(emilio): Should this use the root element's style frame? The root
3442 // frame will always have the initial font. Then again it should never matter
3443 // for content, we should always have a root scrollable frame in html
3444 // documents.
3445 nsIFrame* rootFrame = aPresContext->PresShell()->GetRootFrame();
3446 if (!rootFrame) {
3447 return nsSize(0, 0);
3448 }
3449 RefPtr<nsFontMetrics> fm =
3450 nsLayoutUtils::GetInflatedFontMetricsForFrame(rootFrame);
3451 NS_ENSURE_TRUE(fm, nsSize(0, 0))do { if ((__builtin_expect(!!(!(fm)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "fm" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3451); return nsSize(0, 0); } } while (false)
;
3452 return nsSize(fm->AveCharWidth(), fm->MaxHeight());
3453}
3454
3455void EventStateManager::DoScrollText(
3456 ScrollContainerFrame* aScrollContainerFrame, WidgetWheelEvent* aEvent) {
3457 MOZ_ASSERT(aScrollContainerFrame)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aScrollContainerFrame)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aScrollContainerFrame))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aScrollContainerFrame"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3457); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aScrollContainerFrame"
")"); do { *((volatile int*)__null) = 3457; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3458 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3458); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 3458; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3459
3460 AutoWeakFrame scrollFrameWeak(aScrollContainerFrame);
3461 AutoWeakFrame eventFrameWeak(mCurrentTarget);
3462 if (!WheelTransaction::WillHandleDefaultAction(aEvent, scrollFrameWeak,
3463 eventFrameWeak)) {
3464 return;
3465 }
3466
3467 // Default action's actual scroll amount should be computed from device
3468 // pixels.
3469 nsPresContext* pc = aScrollContainerFrame->PresContext();
3470 nsSize scrollAmount = GetScrollAmount(pc, aEvent, aScrollContainerFrame);
3471 nsIntSize scrollAmountInDevPixels(
3472 pc->AppUnitsToDevPixels(scrollAmount.width),
3473 pc->AppUnitsToDevPixels(scrollAmount.height));
3474 nsIntPoint actualDevPixelScrollAmount =
3475 DeltaAccumulator::GetInstance()->ComputeScrollAmountForDefaultAction(
3476 aEvent, scrollAmountInDevPixels);
3477
3478 // Don't scroll around the axis whose overflow style is hidden.
3479 ScrollStyles overflowStyle = aScrollContainerFrame->GetScrollStyles();
3480 if (overflowStyle.mHorizontal == StyleOverflow::Hidden) {
3481 actualDevPixelScrollAmount.x = 0;
3482 }
3483 if (overflowStyle.mVertical == StyleOverflow::Hidden) {
3484 actualDevPixelScrollAmount.y = 0;
3485 }
3486
3487 ScrollSnapFlags snapFlags = ScrollSnapFlags::Disabled;
3488 mozilla::ScrollOrigin origin = mozilla::ScrollOrigin::NotSpecified;
3489 switch (aEvent->mDeltaMode) {
3490 case WheelEvent_Binding::DOM_DELTA_LINE:
3491 origin = mozilla::ScrollOrigin::MouseWheel;
3492 snapFlags = ScrollSnapFlags::IntendedDirection;
3493 break;
3494 case WheelEvent_Binding::DOM_DELTA_PAGE:
3495 origin = mozilla::ScrollOrigin::Pages;
3496 snapFlags = ScrollSnapFlags::IntendedDirection |
3497 ScrollSnapFlags::IntendedEndPosition;
3498 break;
3499 case WheelEvent_Binding::DOM_DELTA_PIXEL:
3500 origin = mozilla::ScrollOrigin::Pixels;
3501 break;
3502 default:
3503 MOZ_CRASH("Invalid deltaMode value comes")do { do { } while (false); MOZ_ReportCrash("" "Invalid deltaMode value comes"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3503); AnnotateMozCrashReason("MOZ_CRASH(" "Invalid deltaMode value comes"
")"); do { *((volatile int*)__null) = 3503; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
3504 }
3505
3506 // We shouldn't scroll more one page at once except when over one page scroll
3507 // is allowed for the event.
3508 nsSize pageSize = aScrollContainerFrame->GetPageScrollAmount();
3509 nsIntSize devPixelPageSize(pc->AppUnitsToDevPixels(pageSize.width),
3510 pc->AppUnitsToDevPixels(pageSize.height));
3511 if (!WheelPrefs::GetInstance()->IsOverOnePageScrollAllowedX(aEvent) &&
3512 DeprecatedAbs(actualDevPixelScrollAmount.x.value) >
3513 devPixelPageSize.width) {
3514 actualDevPixelScrollAmount.x = (actualDevPixelScrollAmount.x >= 0)
3515 ? devPixelPageSize.width
3516 : -devPixelPageSize.width;
3517 }
3518
3519 if (!WheelPrefs::GetInstance()->IsOverOnePageScrollAllowedY(aEvent) &&
3520 DeprecatedAbs(actualDevPixelScrollAmount.y.value) >
3521 devPixelPageSize.height) {
3522 actualDevPixelScrollAmount.y = (actualDevPixelScrollAmount.y >= 0)
3523 ? devPixelPageSize.height
3524 : -devPixelPageSize.height;
3525 }
3526
3527 bool isDeltaModePixel =
3528 (aEvent->mDeltaMode == WheelEvent_Binding::DOM_DELTA_PIXEL);
3529
3530 ScrollMode mode;
3531 switch (aEvent->mScrollType) {
3532 case WidgetWheelEvent::SCROLL_DEFAULT:
3533 if (isDeltaModePixel) {
3534 mode = ScrollMode::Normal;
3535 } else if (aEvent->mFlags.mHandledByAPZ) {
3536 mode = ScrollMode::SmoothMsd;
3537 } else {
3538 mode = ScrollMode::Smooth;
3539 }
3540 break;
3541 case WidgetWheelEvent::SCROLL_SYNCHRONOUSLY:
3542 mode = ScrollMode::Instant;
3543 break;
3544 case WidgetWheelEvent::SCROLL_ASYNCHRONOUSLY:
3545 mode = ScrollMode::Normal;
3546 break;
3547 case WidgetWheelEvent::SCROLL_SMOOTHLY:
3548 mode = ScrollMode::Smooth;
3549 break;
3550 default:
3551 MOZ_CRASH("Invalid mScrollType value comes")do { do { } while (false); MOZ_ReportCrash("" "Invalid mScrollType value comes"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3551); AnnotateMozCrashReason("MOZ_CRASH(" "Invalid mScrollType value comes"
")"); do { *((volatile int*)__null) = 3551; __attribute__((nomerge
)) ::abort(); } while (false); } while (false)
;
3552 }
3553
3554 ScrollContainerFrame::ScrollMomentum momentum =
3555 aEvent->mIsMomentum ? ScrollContainerFrame::SYNTHESIZED_MOMENTUM_EVENT
3556 : ScrollContainerFrame::NOT_MOMENTUM;
3557
3558 nsIntPoint overflow;
3559 aScrollContainerFrame->ScrollBy(actualDevPixelScrollAmount,
3560 ScrollUnit::DEVICE_PIXELS, mode, &overflow,
3561 origin, momentum, snapFlags);
3562
3563 if (!scrollFrameWeak.IsAlive()) {
3564 // If the scroll causes changing the layout, we can think that the event
3565 // has been completely consumed by the content. Then, users probably don't
3566 // want additional action.
3567 aEvent->mOverflowDeltaX = aEvent->mOverflowDeltaY = 0;
3568 } else if (isDeltaModePixel) {
3569 aEvent->mOverflowDeltaX = overflow.x;
3570 aEvent->mOverflowDeltaY = overflow.y;
3571 } else {
3572 aEvent->mOverflowDeltaX =
3573 static_cast<double>(overflow.x) / scrollAmountInDevPixels.width;
3574 aEvent->mOverflowDeltaY =
3575 static_cast<double>(overflow.y) / scrollAmountInDevPixels.height;
3576 }
3577
3578 // If CSS overflow properties caused not to scroll, the overflowDelta* values
3579 // should be same as delta* values since they may be used as gesture event by
3580 // widget. However, if there is another scrollable element in the ancestor
3581 // along the axis, probably users don't want the operation to cause
3582 // additional action such as moving history. In such case, overflowDelta
3583 // values should stay zero.
3584 if (scrollFrameWeak.IsAlive()) {
3585 if (aEvent->mDeltaX && overflowStyle.mHorizontal == StyleOverflow::Hidden &&
3586 !ComputeScrollTargetAndMayAdjustWheelEvent(
3587 aScrollContainerFrame, aEvent,
3588 COMPUTE_SCROLLABLE_ANCESTOR_ALONG_X_AXIS_WITH_AUTO_DIR)) {
3589 aEvent->mOverflowDeltaX = aEvent->mDeltaX;
3590 }
3591 if (aEvent->mDeltaY && overflowStyle.mVertical == StyleOverflow::Hidden &&
3592 !ComputeScrollTargetAndMayAdjustWheelEvent(
3593 aScrollContainerFrame, aEvent,
3594 COMPUTE_SCROLLABLE_ANCESTOR_ALONG_Y_AXIS_WITH_AUTO_DIR)) {
3595 aEvent->mOverflowDeltaY = aEvent->mDeltaY;
3596 }
3597 }
3598
3599 NS_ASSERTION(do { if (!(aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX
> 0) == (aEvent->mDeltaX > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaX is different from the scroll direction"
, "aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3602); MOZ_PretendNoReturn(); } } while (0)
3600 aEvent->mOverflowDeltaX == 0 ||do { if (!(aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX
> 0) == (aEvent->mDeltaX > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaX is different from the scroll direction"
, "aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3602); MOZ_PretendNoReturn(); } } while (0)
3601 (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0),do { if (!(aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX
> 0) == (aEvent->mDeltaX > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaX is different from the scroll direction"
, "aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3602); MOZ_PretendNoReturn(); } } while (0)
3602 "The sign of mOverflowDeltaX is different from the scroll direction")do { if (!(aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX
> 0) == (aEvent->mDeltaX > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaX is different from the scroll direction"
, "aEvent->mOverflowDeltaX == 0 || (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3602); MOZ_PretendNoReturn(); } } while (0)
;
3603 NS_ASSERTION(do { if (!(aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY
> 0) == (aEvent->mDeltaY > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaY is different from the scroll direction"
, "aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3606); MOZ_PretendNoReturn(); } } while (0)
3604 aEvent->mOverflowDeltaY == 0 ||do { if (!(aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY
> 0) == (aEvent->mDeltaY > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaY is different from the scroll direction"
, "aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3606); MOZ_PretendNoReturn(); } } while (0)
3605 (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0),do { if (!(aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY
> 0) == (aEvent->mDeltaY > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaY is different from the scroll direction"
, "aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3606); MOZ_PretendNoReturn(); } } while (0)
3606 "The sign of mOverflowDeltaY is different from the scroll direction")do { if (!(aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY
> 0) == (aEvent->mDeltaY > 0))) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "The sign of mOverflowDeltaY is different from the scroll direction"
, "aEvent->mOverflowDeltaY == 0 || (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3606); MOZ_PretendNoReturn(); } } while (0)
;
3607
3608 WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(aEvent);
3609}
3610
3611void EventStateManager::DecideGestureEvent(WidgetGestureNotifyEvent* aEvent,
3612 nsIFrame* targetFrame) {
3613 NS_ASSERTION(aEvent->mMessage == eGestureNotify,do { if (!(aEvent->mMessage == eGestureNotify)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "DecideGestureEvent called with a non-gesture event"
, "aEvent->mMessage == eGestureNotify", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3614); MOZ_PretendNoReturn(); } } while (0)
3614 "DecideGestureEvent called with a non-gesture event")do { if (!(aEvent->mMessage == eGestureNotify)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "DecideGestureEvent called with a non-gesture event"
, "aEvent->mMessage == eGestureNotify", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3614); MOZ_PretendNoReturn(); } } while (0)
;
3615
3616 /* Check the ancestor tree to decide if any frame is willing* to receive
3617 * a MozPixelScroll event. If that's the case, the current touch gesture
3618 * will be used as a pan gesture; otherwise it will be a regular
3619 * mousedown/mousemove/click event.
3620 *
3621 * *willing: determine if it makes sense to pan the element using scroll
3622 * events:
3623 * - For web content: if there are any visible scrollbars on the touch point
3624 * - For XUL: if it's an scrollable element that can currently scroll in some
3625 * direction.
3626 *
3627 * Note: we'll have to one-off various cases to ensure a good usable behavior
3628 */
3629 WidgetGestureNotifyEvent::PanDirection panDirection =
3630 WidgetGestureNotifyEvent::ePanNone;
3631 bool displayPanFeedback = false;
3632 for (nsIFrame* current = targetFrame; current;
3633 current = nsLayoutUtils::GetCrossDocParentFrame(current)) {
3634 // e10s - mark remote content as pannable. This is a work around since
3635 // we don't have access to remote frame scroll info here. Apz data may
3636 // assist is solving this.
3637 if (current && IsTopLevelRemoteTarget(current->GetContent())) {
3638 panDirection = WidgetGestureNotifyEvent::ePanBoth;
3639 // We don't know when we reach bounds, so just disable feedback for now.
3640 displayPanFeedback = false;
3641 break;
3642 }
3643
3644 LayoutFrameType currentFrameType = current->Type();
3645
3646 // Scrollbars should always be draggable
3647 if (currentFrameType == LayoutFrameType::Scrollbar) {
3648 panDirection = WidgetGestureNotifyEvent::ePanNone;
3649 break;
3650 }
3651
3652 // Special check for trees
3653 if (nsTreeBodyFrame* treeFrame = do_QueryFrame(current)) {
3654 if (treeFrame->GetVerticalOverflow()) {
3655 panDirection = WidgetGestureNotifyEvent::ePanVertical;
3656 }
3657 break;
3658 }
3659
3660 if (ScrollContainerFrame* scrollContainerFrame = do_QueryFrame(current)) {
3661 layers::ScrollDirections scrollbarVisibility =
3662 scrollContainerFrame->GetScrollbarVisibility();
3663
3664 // Check if we have visible scrollbars
3665 if (scrollbarVisibility.contains(layers::ScrollDirection::eVertical)) {
3666 panDirection = WidgetGestureNotifyEvent::ePanVertical;
3667 displayPanFeedback = true;
3668 break;
3669 }
3670
3671 if (scrollbarVisibility.contains(layers::ScrollDirection::eHorizontal)) {
3672 panDirection = WidgetGestureNotifyEvent::ePanHorizontal;
3673 displayPanFeedback = true;
3674 }
3675 }
3676 } // ancestor chain
3677 aEvent->mDisplayPanFeedback = displayPanFeedback;
3678 aEvent->mPanDirection = panDirection;
3679}
3680
3681#ifdef XP_MACOSX
3682static nsINode* GetCrossDocParentNode(nsINode* aChild) {
3683 MOZ_ASSERT(aChild, "The child is null!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChild)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aChild))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aChild" " (" "The child is null!"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3683); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChild" ") ("
"The child is null!" ")"); do { *((volatile int*)__null) = 3683
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
3684 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3684); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 3684; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3685
3686 nsINode* parent = aChild->GetParentNode();
3687 if (parent && parent->IsContent() && aChild->IsContent()) {
3688 parent = aChild->AsContent()->GetFlattenedTreeParent();
3689 }
3690
3691 if (parent || !aChild->IsDocument()) {
3692 return parent;
3693 }
3694
3695 return aChild->AsDocument()->GetEmbedderElement();
3696}
3697
3698static bool NodeAllowsClickThrough(nsINode* aNode) {
3699 while (aNode) {
3700 if (aNode->IsAnyOfXULElements(nsGkAtoms::browser, nsGkAtoms::tree)) {
3701 return false;
3702 }
3703 if (aNode->IsAnyOfXULElements(nsGkAtoms::scrollbar, nsGkAtoms::resizer)) {
3704 return true;
3705 }
3706 aNode = GetCrossDocParentNode(aNode);
3707 }
3708 return true;
3709}
3710#endif
3711
3712void EventStateManager::PostHandleKeyboardEvent(
3713 WidgetKeyboardEvent* aKeyboardEvent, nsIFrame* aTargetFrame,
3714 nsEventStatus& aStatus) {
3715 if (aStatus == nsEventStatus_eConsumeNoDefault) {
3716 return;
3717 }
3718
3719 RefPtr<nsPresContext> presContext = mPresContext;
3720
3721 if (!aKeyboardEvent->HasBeenPostedToRemoteProcess()) {
3722 if (aKeyboardEvent->IsWaitingReplyFromRemoteProcess()) {
3723 RefPtr<BrowserParent> remote =
3724 aTargetFrame ? BrowserParent::GetFrom(aTargetFrame->GetContent())
3725 : nullptr;
3726 if (remote) {
3727 // remote is null-checked above in order to let pre-existing event
3728 // targeting code's chrome vs. content decision override in case of
3729 // disagreement in order not to disrupt non-Fission e10s mode in case
3730 // there are still bugs in the Fission-mode code. That is, if remote
3731 // is nullptr, the pre-existing event targeting code has deemed this
3732 // event to belong to chrome rather than content.
3733 BrowserParent* preciseRemote = BrowserParent::GetFocused();
3734 if (preciseRemote) {
3735 remote = preciseRemote;
3736 }
3737 // else there was a race between layout and focus tracking
3738 }
3739 if (remote && !remote->IsReadyToHandleInputEvents()) {
3740 // We need to dispatch the event to the browser element again if we were
3741 // waiting for the key reply but the event wasn't sent to the content
3742 // process due to the remote browser wasn't ready.
3743 WidgetKeyboardEvent keyEvent(*aKeyboardEvent);
3744 aKeyboardEvent->MarkAsHandledInRemoteProcess();
3745 RefPtr<Element> ownerElement = remote->GetOwnerElement();
3746 EventDispatcher::Dispatch(ownerElement, presContext, &keyEvent);
3747 if (keyEvent.DefaultPrevented()) {
3748 aKeyboardEvent->PreventDefault(!keyEvent.DefaultPreventedByContent());
3749 aStatus = nsEventStatus_eConsumeNoDefault;
3750 return;
3751 }
3752 }
3753 }
3754 // The widget expects a reply for every keyboard event. If the event wasn't
3755 // dispatched to a content process (non-e10s or no content process
3756 // running), we need to short-circuit here. Otherwise, we need to wait for
3757 // the content process to handle the event.
3758 if (aKeyboardEvent->mWidget) {
3759 aKeyboardEvent->mWidget->PostHandleKeyEvent(aKeyboardEvent);
3760 }
3761 if (aKeyboardEvent->DefaultPrevented()) {
3762 aStatus = nsEventStatus_eConsumeNoDefault;
3763 return;
3764 }
3765 }
3766
3767 // XXX Currently, our automated tests don't support mKeyNameIndex.
3768 // Therefore, we still need to handle this with keyCode.
3769 switch (aKeyboardEvent->mKeyCode) {
3770 case NS_VK_TAB:
3771 case NS_VK_F6:
3772 // This is to prevent keyboard scrolling while alt modifier in use.
3773 if (!aKeyboardEvent->IsAlt()) {
3774 aStatus = nsEventStatus_eConsumeNoDefault;
3775
3776 // Handling the tab event after it was sent to content is bad,
3777 // because to the FocusManager the remote-browser looks like one
3778 // element, so we would just move the focus to the next element
3779 // in chrome, instead of handling it in content.
3780 if (aKeyboardEvent->HasBeenPostedToRemoteProcess()) {
3781 break;
3782 }
3783
3784 EnsureDocument(presContext);
3785 nsFocusManager* fm = nsFocusManager::GetFocusManager();
3786 if (fm && mDocument) {
3787 // Shift focus forward or back depending on shift key
3788 bool isDocMove = aKeyboardEvent->IsControl() ||
3789 aKeyboardEvent->mKeyCode == NS_VK_F6;
3790 uint32_t dir =
3791 aKeyboardEvent->IsShift()
3792 ? (isDocMove ? static_cast<uint32_t>(
3793 nsIFocusManager::MOVEFOCUS_BACKWARDDOC)
3794 : static_cast<uint32_t>(
3795 nsIFocusManager::MOVEFOCUS_BACKWARD))
3796 : (isDocMove ? static_cast<uint32_t>(
3797 nsIFocusManager::MOVEFOCUS_FORWARDDOC)
3798 : static_cast<uint32_t>(
3799 nsIFocusManager::MOVEFOCUS_FORWARD));
3800 RefPtr<Element> result;
3801 fm->MoveFocus(mDocument->GetWindow(), nullptr, dir,
3802 nsIFocusManager::FLAG_BYKEY, getter_AddRefs(result));
3803 }
3804 }
3805 return;
3806 case 0:
3807 // We handle keys with no specific keycode value below.
3808 break;
3809 default:
3810 return;
3811 }
3812
3813 switch (aKeyboardEvent->mKeyNameIndex) {
3814 case KEY_NAME_INDEX_ZoomIn:
3815 case KEY_NAME_INDEX_ZoomOut:
3816 ChangeZoom(aKeyboardEvent->mKeyNameIndex == KEY_NAME_INDEX_ZoomIn);
3817 aStatus = nsEventStatus_eConsumeNoDefault;
3818 break;
3819 default:
3820 break;
3821 }
3822}
3823
3824static bool NeedsActiveContentChange(const WidgetMouseEvent* aMouseEvent) {
3825 // If the mouse event is a synthesized mouse event due to a touch, do
3826 // not set/clear the activation state. Element activation is handled by APZ.
3827 return !aMouseEvent ||
3828 aMouseEvent->mInputSource != MouseEvent_Binding::MOZ_SOURCE_TOUCH;
3829}
3830
3831nsresult EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
3832 WidgetEvent* aEvent,
3833 nsIFrame* aTargetFrame,
3834 nsEventStatus* aStatus,
3835 nsIContent* aOverrideClickTarget) {
3836 AUTO_PROFILER_LABEL("EventStateManager::PostHandleEvent", DOM)mozilla::AutoProfilerLabel raiiObject3836( "EventStateManager::PostHandleEvent"
, nullptr, JS::ProfilingCategoryPair::DOM)
;
3837 NS_ENSURE_ARG(aPresContext)do { if ((__builtin_expect(!!(!(aPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3837); return NS_ERROR_INVALID_ARG; } } while (false)
;
3838 NS_ENSURE_ARG_POINTER(aStatus)do { if ((__builtin_expect(!!(!(aStatus)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aStatus" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 3838); return NS_ERROR_INVALID_POINTER; } } while (false)
;
3839
3840 mCurrentTarget = aTargetFrame;
3841 mCurrentTargetContent = nullptr;
3842
3843 HandleCrossProcessEvent(aEvent, aStatus);
3844 // NOTE: the above call may have destroyed aTargetFrame, please use
3845 // mCurrentTarget henceforth. This is to avoid using it accidentally:
3846 aTargetFrame = nullptr;
3847
3848 // Most of the events we handle below require a frame.
3849 // Add special cases here.
3850 if (!mCurrentTarget && aEvent->mMessage != eMouseUp &&
3851 aEvent->mMessage != eMouseDown && aEvent->mMessage != eDragEnter &&
3852 aEvent->mMessage != eDragOver && aEvent->mMessage != ePointerUp &&
3853 aEvent->mMessage != ePointerCancel) {
3854 return NS_OK;
3855 }
3856
3857 // Keep the prescontext alive, we might need it after event dispatch
3858 RefPtr<nsPresContext> presContext = aPresContext;
3859 nsresult ret = NS_OK;
3860
3861 switch (aEvent->mMessage) {
3862 case eMouseDown: {
3863 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
3864 if (mouseEvent->mButton == MouseButton::ePrimary &&
3865 !sNormalLMouseEventInProcess) {
3866 // We got a mouseup event while a mousedown event was being processed.
3867 // Make sure that the capturing content is cleared.
3868 PresShell::ReleaseCapturingContent();
3869 break;
3870 }
3871
3872 // For remote content, capture the event in the parent process at the
3873 // <xul:browser remote> element. This will ensure that subsequent
3874 // mousemove/mouseup events will continue to be dispatched to this element
3875 // and therefore forwarded to the child.
3876 if (aEvent->HasBeenPostedToRemoteProcess() &&
3877 !PresShell::GetCapturingContent()) {
3878 if (nsIContent* content =
3879 mCurrentTarget ? mCurrentTarget->GetContent() : nullptr) {
3880 PresShell::SetCapturingContent(content, CaptureFlags::None, aEvent);
3881 } else {
3882 PresShell::ReleaseCapturingContent();
3883 }
3884 }
3885
3886 // If MouseEvent::PreventClickEvent() was called by chrome script,
3887 // we need to forget the clicking content and click count for the
3888 // following eMouseUp event.
3889 if (mouseEvent->mClickEventPrevented) {
3890 switch (mouseEvent->mButton) {
3891 case MouseButton::ePrimary:
3892 case MouseButton::eSecondary:
3893 case MouseButton::eMiddle: {
3894 LastMouseDownInfo& mouseDownInfo =
3895 GetLastMouseDownInfo(mouseEvent->mButton);
3896 mouseDownInfo.mLastMouseDownContent = nullptr;
3897 mouseDownInfo.mClickCount = 0;
3898 mouseDownInfo.mLastMouseDownInputControlType = Nothing();
3899 break;
3900 }
3901
3902 default:
3903 break;
3904 }
3905 }
3906
3907 nsCOMPtr<nsIContent> activeContent;
3908 // When content calls PreventDefault on pointerdown, we also call
3909 // PreventDefault on the subsequent mouse events to suppress default
3910 // behaviors. Normally, aStatus should be nsEventStatus_eConsumeNoDefault
3911 // when the event is DefaultPrevented but it's reset to
3912 // nsEventStatus_eIgnore in EventStateManager::PreHandleEvent. So we also
3913 // check if the event is DefaultPrevented.
3914 if (nsEventStatus_eConsumeNoDefault != *aStatus &&
3915 !aEvent->DefaultPrevented()) {
3916 nsCOMPtr<nsIContent> newFocus;
3917 bool suppressBlur = false;
3918 if (mCurrentTarget) {
3919 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(newFocus));
3920 activeContent = mCurrentTarget->GetContent();
3921
3922 // In some cases, we do not want to even blur the current focused
3923 // element. Those cases are:
3924 // 1. -moz-user-focus CSS property is set to 'ignore';
3925 // 2. XUL control element has the disabled property set to 'true'.
3926 //
3927 // We can't use nsIFrame::IsFocusable() because we want to blur when
3928 // we click on a visibility: none element.
3929 // We can't use nsIContent::IsFocusable() because we want to blur when
3930 // we click on a non-focusable element like a <div>.
3931 // We have to use |aEvent->mTarget| to not make sure we do not check
3932 // an anonymous node of the targeted element.
3933 suppressBlur =
3934 mCurrentTarget->StyleUI()->UserFocus() == StyleUserFocus::Ignore;
3935
3936 if (!suppressBlur) {
3937 if (Element* element =
3938 Element::FromEventTargetOrNull(aEvent->mTarget)) {
3939 if (nsCOMPtr<nsIDOMXULControlElement> xulControl =
3940 element->AsXULControl()) {
3941 bool disabled = false;
3942 xulControl->GetDisabled(&disabled);
3943 suppressBlur = disabled;
3944 }
3945 }
3946 }
3947 }
3948
3949 // When a root content which isn't editable but has an editable HTML
3950 // <body> element is clicked, we should redirect the focus to the
3951 // the <body> element. E.g., when an user click bottom of the editor
3952 // where is outside of the <body> element, the <body> should be focused
3953 // and the user can edit immediately after that.
3954 //
3955 // NOTE: The newFocus isn't editable that also means it's not in
3956 // designMode. In designMode, all contents are not focusable.
3957 if (newFocus && !newFocus->IsEditable()) {
3958 Document* doc = newFocus->GetComposedDoc();
3959 if (doc && newFocus == doc->GetRootElement()) {
3960 nsIContent* bodyContent =
3961 nsLayoutUtils::GetEditableRootContentByContentEditable(doc);
3962 if (bodyContent && bodyContent->GetPrimaryFrame()) {
3963 newFocus = bodyContent;
3964 }
3965 }
3966 }
3967
3968 // When the mouse is pressed, the default action is to focus the
3969 // target. Look for the nearest enclosing focusable frame.
3970 //
3971 // TODO: Probably this should be moved to Element::PostHandleEvent.
3972 for (; newFocus; newFocus = newFocus->GetFlattenedTreeParent()) {
3973 if (!newFocus->IsElement()) {
3974 continue;
3975 }
3976
3977 nsIFrame* frame = newFocus->GetPrimaryFrame();
3978 if (!frame) {
3979 continue;
3980 }
3981
3982 // If the mousedown happened inside a popup, don't try to set focus on
3983 // one of its containing elements
3984 if (frame->IsMenuPopupFrame()) {
3985 newFocus = nullptr;
3986 break;
3987 }
3988
3989 auto flags = IsFocusableFlags::WithMouse;
3990 if (frame->IsFocusable(flags)) {
3991 break;
3992 }
3993
3994 if (ShadowRoot* root = newFocus->GetShadowRoot()) {
3995 if (root->DelegatesFocus()) {
3996 if (Element* firstFocusable = root->GetFocusDelegate(flags)) {
3997 newFocus = firstFocusable;
3998 break;
3999 }
4000 }
4001 }
4002 }
4003
4004 MOZ_ASSERT_IF(newFocus, newFocus->IsElement())do { if (newFocus) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(newFocus->IsElement())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(newFocus->IsElement()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("newFocus->IsElement()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4004); AnnotateMozCrashReason("MOZ_ASSERT" "(" "newFocus->IsElement()"
")"); do { *((volatile int*)__null) = 4004; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
4005
4006 if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
4007 // if something was found to focus, focus it. Otherwise, if the
4008 // element that was clicked doesn't have -moz-user-focus: ignore,
4009 // clear the existing focus. For -moz-user-focus: ignore, the focus
4010 // is just left as is.
4011 // Another effect of mouse clicking, handled in Selection, is that
4012 // it should update the caret position to where the mouse was
4013 // clicked. Because the focus is cleared when clicking on a
4014 // non-focusable node, the next press of the tab key will cause
4015 // focus to be shifted from the caret position instead of the root.
4016 if (newFocus) {
4017 // use the mouse flag and the noscroll flag so that the content
4018 // doesn't unexpectedly scroll when clicking an element that is
4019 // only half visible
4020 uint32_t flags =
4021 nsIFocusManager::FLAG_BYMOUSE | nsIFocusManager::FLAG_NOSCROLL;
4022 // If this was a touch-generated event, pass that information:
4023 if (mouseEvent->mInputSource ==
4024 MouseEvent_Binding::MOZ_SOURCE_TOUCH) {
4025 flags |= nsIFocusManager::FLAG_BYTOUCH;
4026 }
4027 fm->SetFocus(MOZ_KnownLive(newFocus->AsElement())(newFocus->AsElement()), flags);
4028 } else if (!suppressBlur) {
4029 // clear the focus within the frame and then set it as the
4030 // focused frame
4031 EnsureDocument(mPresContext);
4032 if (mDocument) {
4033 nsCOMPtr<nsPIDOMWindowOuter> outerWindow = mDocument->GetWindow();
4034#ifdef XP_MACOSX
4035 if (!activeContent || !activeContent->IsXULElement())
4036#endif
4037 fm->ClearFocus(outerWindow);
4038 // Prevent switch frame if we're already not in the foreground tab
4039 // and we're in a content process.
4040 // TODO: If we were inactive frame in this tab, and now in
4041 // background tab, we shouldn't make the tab foreground, but
4042 // we should set focus to clicked document in the background
4043 // tab. However, nsFocusManager does not have proper method
4044 // for doing this. Therefore, we should skip setting focus
4045 // to clicked document for now.
4046 if (XRE_IsParentProcess() || IsInActiveTab(mDocument)) {
4047 fm->SetFocusedWindow(outerWindow);
4048 }
4049 }
4050 }
4051 }
4052
4053 // The rest is left button-specific.
4054 if (mouseEvent->mButton != MouseButton::ePrimary) {
4055 break;
4056 }
4057
4058 // The nearest enclosing element goes into the :active state. If we're
4059 // not an element (so we're text or something) we need to obtain
4060 // our parent element and put it into :active instead.
4061 if (activeContent && !activeContent->IsElement()) {
4062 if (nsIContent* par = activeContent->GetFlattenedTreeParent()) {
4063 activeContent = par;
4064 }
4065 }
4066 } else {
4067 // if we're here, the event handler returned false, so stop
4068 // any of our own processing of a drag. Workaround for bug 43258.
4069 StopTrackingDragGesture(true);
4070 }
4071 // XXX Why do we always set this is active? Active window may be changed
4072 // by a mousedown event listener.
4073 if (NeedsActiveContentChange(mouseEvent)) {
4074 SetActiveManager(this, activeContent);
4075 }
4076 } break;
4077 case ePointerCancel:
4078 case ePointerUp: {
4079 WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent();
4080 MOZ_ASSERT(pointerEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(pointerEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pointerEvent))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("pointerEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4080); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pointerEvent"
")"); do { *((volatile int*)__null) = 4080; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4081 // Implicitly releasing capture for given pointer. ePointerLostCapture
4082 // should be send after ePointerUp or ePointerCancel.
4083 PointerEventHandler::ImplicitlyReleasePointerCapture(pointerEvent);
4084 PointerEventHandler::UpdateActivePointerState(pointerEvent);
4085
4086 if (
4087 // After pointercancel, pointer becomes invalid so we can remove
4088 // relevant helper from table.
4089 pointerEvent->mMessage == ePointerCancel ||
4090 // pointerup for non-hoverable pointer needs to dispatch pointerout
4091 // and pointerleave events because the pointer is valid only while the
4092 // pointer is "down".
4093 !pointerEvent->InputSourceSupportsHover()) {
4094 GenerateMouseEnterExit(pointerEvent);
4095 mPointersEnterLeaveHelper.Remove(pointerEvent->pointerId);
4096 }
4097
4098 break;
4099 }
4100 case eMouseUp: {
4101 // We can unconditionally stop capturing because
4102 // we should never be capturing when the mouse button is up
4103 PresShell::ReleaseCapturingContent();
4104
4105 WidgetMouseEvent* mouseUpEvent = aEvent->AsMouseEvent();
4106 if (NeedsActiveContentChange(mouseUpEvent)) {
4107 ClearGlobalActiveContent(this);
4108 }
4109 if (mouseUpEvent && EventCausesClickEvents(*mouseUpEvent)) {
4110 // Make sure to dispatch the click even if there is no frame for
4111 // the current target element. This is required for Web compatibility.
4112 RefPtr<EventStateManager> esm =
4113 ESMFromContentOrThis(aOverrideClickTarget);
4114 ret =
4115 esm->PostHandleMouseUp(mouseUpEvent, aStatus, aOverrideClickTarget);
4116 }
4117
4118 if (PresShell* presShell = presContext->GetPresShell()) {
4119 RefPtr<nsFrameSelection> frameSelection = presShell->FrameSelection();
4120 frameSelection->SetDragState(false);
4121 }
4122 } break;
4123 case eWheelOperationEnd: {
4124 MOZ_ASSERT(aEvent->IsTrusted())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->IsTrusted())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->IsTrusted()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->IsTrusted()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4124); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsTrusted()"
")"); do { *((volatile int*)__null) = 4124; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4125 ScrollbarsForWheel::MayInactivate();
4126 WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
4127 ScrollContainerFrame* scrollTarget =
4128 ComputeScrollTargetAndMayAdjustWheelEvent(
4129 mCurrentTarget, wheelEvent,
4130 COMPUTE_DEFAULT_ACTION_TARGET_WITH_AUTO_DIR);
4131 // If the wheel event was handled by APZ, APZ will perform the scroll
4132 // snap.
4133 if (scrollTarget && !WheelTransaction::HandledByApz()) {
4134 scrollTarget->ScrollSnap();
4135 }
4136 } break;
4137 case eWheel:
4138 case eWheelOperationStart: {
4139 MOZ_ASSERT(aEvent->IsTrusted())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->IsTrusted())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->IsTrusted()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->IsTrusted()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4139); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->IsTrusted()"
")"); do { *((volatile int*)__null) = 4139; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4140
4141 if (*aStatus == nsEventStatus_eConsumeNoDefault) {
4142 ScrollbarsForWheel::Inactivate();
4143 break;
4144 }
4145
4146 WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
4147 MOZ_ASSERT(wheelEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(wheelEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(wheelEvent))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("wheelEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4147); AnnotateMozCrashReason("MOZ_ASSERT" "(" "wheelEvent"
")"); do { *((volatile int*)__null) = 4147; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4148
4149 // When APZ is enabled, the actual scroll animation might be handled by
4150 // the compositor.
4151 WheelPrefs::Action action =
4152 wheelEvent->mFlags.mHandledByAPZ
4153 ? WheelPrefs::ACTION_NONE
4154 : WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent);
4155
4156 WheelDeltaAdjustmentStrategy strategy =
4157 GetWheelDeltaAdjustmentStrategy(*wheelEvent);
4158 // Adjust the delta values of the wheel event if the current default
4159 // action is to horizontalize scrolling. I.e., deltaY values are set to
4160 // deltaX and deltaY and deltaZ values are set to 0.
4161 // If horizontalized, the delta values will be restored and its overflow
4162 // deltaX will become 0 when the WheelDeltaHorizontalizer instance is
4163 // being destroyed.
4164 WheelDeltaHorizontalizer horizontalizer(*wheelEvent);
4165 if (WheelDeltaAdjustmentStrategy::eHorizontalize == strategy) {
4166 horizontalizer.Horizontalize();
4167 }
4168
4169 // Since ComputeScrollTargetAndMayAdjustWheelEvent() may adjust the delta
4170 // if the event is auto-dir. So we use |ESMAutoDirWheelDeltaRestorer|
4171 // here.
4172 // An instance of |ESMAutoDirWheelDeltaRestorer| is used to monitor
4173 // auto-dir adjustment which may happen during its lifetime. If the delta
4174 // values is adjusted during its lifetime, the instance will restore the
4175 // adjusted delta when it's being destrcuted.
4176 ESMAutoDirWheelDeltaRestorer restorer(*wheelEvent);
4177 ScrollContainerFrame* scrollTarget =
4178 ComputeScrollTargetAndMayAdjustWheelEvent(
4179 mCurrentTarget, wheelEvent,
4180 COMPUTE_DEFAULT_ACTION_TARGET_WITH_AUTO_DIR);
4181
4182 switch (action) {
4183 case WheelPrefs::ACTION_SCROLL:
4184 case WheelPrefs::ACTION_HORIZONTALIZED_SCROLL: {
4185 // For scrolling of default action, we should honor the mouse wheel
4186 // transaction.
4187
4188 ScrollbarsForWheel::PrepareToScrollText(this, mCurrentTarget,
4189 wheelEvent);
4190
4191 if (aEvent->mMessage != eWheel ||
4192 (!wheelEvent->mDeltaX && !wheelEvent->mDeltaY)) {
4193 break;
4194 }
4195
4196 ScrollbarsForWheel::SetActiveScrollTarget(scrollTarget);
4197
4198 ScrollContainerFrame* rootScrollContainerFrame =
4199 !mCurrentTarget
4200 ? nullptr
4201 : mCurrentTarget->PresShell()->GetRootScrollContainerFrame();
4202 if (!scrollTarget || scrollTarget == rootScrollContainerFrame) {
4203 wheelEvent->mViewPortIsOverscrolled = true;
4204 }
4205 wheelEvent->mOverflowDeltaX = wheelEvent->mDeltaX;
4206 wheelEvent->mOverflowDeltaY = wheelEvent->mDeltaY;
4207 WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(
4208 wheelEvent);
4209 if (scrollTarget) {
4210 DoScrollText(scrollTarget, wheelEvent);
4211 } else {
4212 WheelTransaction::EndTransaction();
4213 ScrollbarsForWheel::Inactivate();
4214 }
4215 break;
4216 }
4217 case WheelPrefs::ACTION_HISTORY: {
4218 // If this event doesn't cause eLegacyMouseLineOrPageScroll event or
4219 // the direction is oblique, don't perform history back/forward.
4220 int32_t intDelta = wheelEvent->GetPreferredIntDelta();
4221 if (!intDelta) {
4222 break;
4223 }
4224 DoScrollHistory(intDelta);
4225 break;
4226 }
4227 case WheelPrefs::ACTION_ZOOM: {
4228 // If this event doesn't cause eLegacyMouseLineOrPageScroll event or
4229 // the direction is oblique, don't perform zoom in/out.
4230 int32_t intDelta = wheelEvent->GetPreferredIntDelta();
4231 if (!intDelta) {
4232 break;
4233 }
4234 DoScrollZoom(mCurrentTarget, intDelta);
4235 break;
4236 }
4237 case WheelPrefs::ACTION_NONE:
4238 default:
4239 bool allDeltaOverflown = false;
4240 if (StaticPrefs::dom_event_wheel_event_groups_enabled() &&
4241 (wheelEvent->mDeltaX != 0.0 || wheelEvent->mDeltaY != 0.0)) {
4242 if (scrollTarget) {
4243 WheelTransaction::WillHandleDefaultAction(
4244 wheelEvent, scrollTarget, mCurrentTarget);
4245 } else {
4246 WheelTransaction::EndTransaction();
4247 }
4248 }
4249 if (wheelEvent->mFlags.mHandledByAPZ) {
4250 if (wheelEvent->mCanTriggerSwipe) {
4251 // For events that can trigger swipes, APZ needs to know whether
4252 // scrolling is possible in the requested direction. It does this
4253 // by looking at the scroll overflow values on mCanTriggerSwipe
4254 // events after they have been processed.
4255 allDeltaOverflown = !ComputeScrollTarget(
4256 mCurrentTarget, wheelEvent, COMPUTE_DEFAULT_ACTION_TARGET);
4257 }
4258 } else {
4259 // The event was processed neither by APZ nor by us, so all of the
4260 // delta values must be overflown delta values.
4261 allDeltaOverflown = true;
4262 }
4263
4264 if (!allDeltaOverflown) {
4265 break;
4266 }
4267 wheelEvent->mOverflowDeltaX = wheelEvent->mDeltaX;
4268 wheelEvent->mOverflowDeltaY = wheelEvent->mDeltaY;
4269 WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(
4270 wheelEvent);
4271 wheelEvent->mViewPortIsOverscrolled = true;
4272 break;
4273 }
4274 *aStatus = nsEventStatus_eConsumeNoDefault;
4275 } break;
4276
4277 case eGestureNotify: {
4278 if (nsEventStatus_eConsumeNoDefault != *aStatus) {
4279 DecideGestureEvent(aEvent->AsGestureNotifyEvent(), mCurrentTarget);
4280 }
4281 } break;
4282
4283 case eDragEnter:
4284 case eDragOver: {
4285 NS_ASSERTION(aEvent->mClass == eDragEventClass, "Expected a drag event")do { if (!(aEvent->mClass == eDragEventClass)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Expected a drag event", "aEvent->mClass == eDragEventClass"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4285); MOZ_PretendNoReturn(); } } while (0)
;
4286
4287 // Check if the drag is occurring inside a scrollable area. If so, scroll
4288 // the area when the mouse is near the edges.
4289 if (mCurrentTarget && aEvent->mMessage == eDragOver) {
4290 nsIFrame* checkFrame = mCurrentTarget;
4291 while (checkFrame) {
4292 ScrollContainerFrame* scrollFrame = do_QueryFrame(checkFrame);
4293 // Break out so only the innermost scrollframe is scrolled.
4294 if (scrollFrame && scrollFrame->DragScroll(aEvent)) {
4295 break;
4296 }
4297 checkFrame = checkFrame->GetParent();
4298 }
4299 }
4300
4301 nsCOMPtr<nsIDragSession> dragSession =
4302 nsContentUtils::GetDragSession(mPresContext);
4303 if (!dragSession) break;
4304
4305 // Reset the flag.
4306 dragSession->SetOnlyChromeDrop(false);
4307 if (mPresContext) {
4308 EnsureDocument(mPresContext);
4309 }
4310 bool isChromeDoc = nsContentUtils::IsChromeDoc(mDocument);
4311
4312 // the initial dataTransfer is the one from the dragstart event that
4313 // was set on the dragSession when the drag began.
4314 RefPtr<DataTransfer> dataTransfer;
4315 RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer();
4316
4317 WidgetDragEvent* dragEvent = aEvent->AsDragEvent();
4318
4319 // collect any changes to moz cursor settings stored in the event's
4320 // data transfer.
4321 UpdateDragDataTransfer(dragEvent);
4322
4323 // cancelling a dragenter or dragover event means that a drop should be
4324 // allowed, so update the dropEffect and the canDrop state to indicate
4325 // that a drag is allowed. If the event isn't cancelled, a drop won't be
4326 // allowed. Essentially, to allow a drop somewhere, specify the effects
4327 // using the effectAllowed and dropEffect properties in a dragenter or
4328 // dragover event and cancel the event. To not allow a drop somewhere,
4329 // don't cancel the event or set the effectAllowed or dropEffect to
4330 // "none". This way, if the event is just ignored, no drop will be
4331 // allowed.
4332 uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
4333 uint32_t action = nsIDragService::DRAGDROP_ACTION_NONE;
4334 if (nsEventStatus_eConsumeNoDefault == *aStatus) {
4335 // If the event has initialized its mDataTransfer, use it.
4336 // Or the event has not been initialized its mDataTransfer, but
4337 // it's set before dispatch because of synthesized, but without
4338 // testing session (e.g., emulating drag from another app), use it
4339 // coming from outside.
4340 // XXX Perhaps, for the latter case, we need new API because we don't
4341 // have a chance to initialize allowed effects of the session.
4342 if (dragEvent->mDataTransfer) {
4343 // get the dataTransfer and the dropEffect that was set on it
4344 dataTransfer = dragEvent->mDataTransfer;
4345 dropEffect = dataTransfer->DropEffectInt();
4346 } else {
4347 // if dragEvent->mDataTransfer is null, it means that no attempt was
4348 // made to access the dataTransfer during the event, yet the event
4349 // was cancelled. Instead, use the initial data transfer available
4350 // from the drag session. The drop effect would not have been
4351 // initialized (which is done in DragEvent::GetDataTransfer),
4352 // so set it from the drag action. We'll still want to filter it
4353 // based on the effectAllowed below.
4354 dataTransfer = initialDataTransfer;
4355
4356 dragSession->GetDragAction(&action);
4357
4358 // filter the drop effect based on the action. Use UNINITIALIZED as
4359 // any effect is allowed.
4360 dropEffect = nsContentUtils::FilterDropEffect(
4361 action, nsIDragService::DRAGDROP_ACTION_UNINITIALIZED);
4362 }
4363
4364 // At this point, if the dataTransfer is null, it means that the
4365 // drag was originally started by directly calling the drag service.
4366 // Just assume that all effects are allowed.
4367 uint32_t effectAllowed = nsIDragService::DRAGDROP_ACTION_UNINITIALIZED;
4368 if (dataTransfer) {
4369 effectAllowed = dataTransfer->EffectAllowedInt();
4370 }
4371
4372 // set the drag action based on the drop effect and effect allowed.
4373 // The drop effect field on the drag transfer object specifies the
4374 // desired current drop effect. However, it cannot be used if the
4375 // effectAllowed state doesn't include that type of action. If the
4376 // dropEffect is "none", then the action will be 'none' so a drop will
4377 // not be allowed.
4378 if (effectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED ||
4379 dropEffect & effectAllowed)
4380 action = dropEffect;
4381
4382 if (action == nsIDragService::DRAGDROP_ACTION_NONE)
4383 dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
4384
4385 // inform the drag session that a drop is allowed on this node.
4386 dragSession->SetDragAction(action);
4387 dragSession->SetCanDrop(action != nsIDragService::DRAGDROP_ACTION_NONE);
4388
4389 // For now, do this only for dragover.
4390 // XXXsmaug dragenter needs some more work.
4391 if (aEvent->mMessage == eDragOver && !isChromeDoc) {
4392 // Someone has called preventDefault(), check whether is was on
4393 // content or chrome.
4394 dragSession->SetOnlyChromeDrop(
4395 !dragEvent->mDefaultPreventedOnContent);
4396 }
4397 } else if (aEvent->mMessage == eDragOver && !isChromeDoc) {
4398 // No one called preventDefault(), so handle drop only in chrome.
4399 dragSession->SetOnlyChromeDrop(true);
4400 }
4401 if (auto* bc = BrowserChild::GetFrom(presContext->GetDocShell())) {
4402 bc->SendUpdateDropEffect(action, dropEffect);
4403 }
4404 if (aEvent->HasBeenPostedToRemoteProcess()) {
4405 dragSession->SetCanDrop(true);
4406 } else if (initialDataTransfer) {
4407 // Now set the drop effect in the initial dataTransfer. This ensures
4408 // that we can get the desired drop effect in the drop event. For events
4409 // dispatched to content, the content process will take care of setting
4410 // this.
4411 initialDataTransfer->SetDropEffectInt(dropEffect);
4412 }
4413 } break;
4414
4415 case eDrop: {
4416 if (aEvent->mFlags.mIsSynthesizedForTests) {
4417 nsCOMPtr<nsIDragService> dragService =
4418 do_GetService("@mozilla.org/widget/dragservice;1");
4419 nsCOMPtr<nsIDragSession> dragSession =
4420 nsContentUtils::GetDragSession(mPresContext);
4421 if (dragSession && dragService &&
4422 !dragService->GetNeverAllowSessionIsSynthesizedForTests()) {
4423 MOZ_ASSERT(dragSession->IsSynthesizedForTests())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(dragSession->IsSynthesizedForTests())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(dragSession->IsSynthesizedForTests()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("dragSession->IsSynthesizedForTests()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4423); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dragSession->IsSynthesizedForTests()"
")"); do { *((volatile int*)__null) = 4423; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4424 RefPtr<WindowContext> sourceWC;
4425 DebugOnly<nsresult> rvIgnored =
4426 dragSession->GetSourceWindowContext(getter_AddRefs(sourceWC));
4427 NS_WARNING_ASSERTION(do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "nsIDragSession::GetSourceDocument() failed, but ignored"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4429); } } while (false)
4428 NS_SUCCEEDED(rvIgnored),do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "nsIDragSession::GetSourceDocument() failed, but ignored"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4429); } } while (false)
4429 "nsIDragSession::GetSourceDocument() failed, but ignored")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "nsIDragSession::GetSourceDocument() failed, but ignored"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4429); } } while (false)
;
4430 // If the drag source hasn't been initialized, i.e., dragstart was
4431 // consumed by the test, the test needs to dispatch "dragend" event
4432 // instead of the drag session. Therefore, it does not make sense
4433 // to set drag end point in such case (you hit assersion if you do
4434 // it).
4435 if (sourceWC) {
4436 const CSSIntPoint dropPointInScreen = RoundedToInt(
4437 Event::GetScreenCoords(aPresContext, aEvent, aEvent->mRefPoint)
4438 .extract());
4439 dragSession->SetDragEndPointForTests(dropPointInScreen.x,
4440 dropPointInScreen.y);
4441 }
4442 }
4443 }
4444 sLastDragOverFrame = nullptr;
4445 ClearGlobalActiveContent(this);
4446 break;
4447 }
4448 case eDragExit: {
4449 // make sure to fire the enter and exit_synth events after the
4450 // eDragExit event, otherwise we'll clean up too early
4451 GenerateDragDropEnterExit(presContext, aEvent->AsDragEvent());
4452 if (auto* bc = BrowserChild::GetFrom(presContext->GetDocShell())) {
4453 // SendUpdateDropEffect to prevent nsIDragService from waiting for
4454 // response of forwarded dragexit event.
4455 bc->SendUpdateDropEffect(nsIDragService::DRAGDROP_ACTION_NONE,
4456 nsIDragService::DRAGDROP_ACTION_NONE);
4457 }
4458 break;
4459 }
4460 case eKeyUp:
4461 // If space key is released, we need to inactivate the element which was
4462 // activated by preceding space key down.
4463 // XXX Currently, we don't store the reason of activation. Therefore,
4464 // this may cancel what is activated by a mousedown, but it must not
4465 // cause actual problem in web apps in the wild since it must be
4466 // rare case that users release space key during a mouse click/drag.
4467 if (aEvent->AsKeyboardEvent()->ShouldWorkAsSpaceKey()) {
4468 ClearGlobalActiveContent(this);
4469 }
4470 break;
4471
4472 case eKeyPress: {
4473 WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
4474 PostHandleKeyboardEvent(keyEvent, mCurrentTarget, *aStatus);
4475 } break;
4476
4477 case eMouseEnterIntoWidget:
4478 if (mCurrentTarget) {
4479 nsCOMPtr<nsIContent> targetContent;
4480 mCurrentTarget->GetContentForEvent(aEvent,
4481 getter_AddRefs(targetContent));
4482 SetContentState(targetContent, ElementState::HOVER);
4483 }
4484 break;
4485
4486 case eMouseExitFromWidget:
4487 PointerEventHandler::UpdateActivePointerState(aEvent->AsMouseEvent());
4488 break;
4489
4490#ifdef XP_MACOSX
4491 case eMouseActivate:
4492 if (mCurrentTarget) {
4493 nsCOMPtr<nsIContent> targetContent;
4494 mCurrentTarget->GetContentForEvent(aEvent,
4495 getter_AddRefs(targetContent));
4496 if (!NodeAllowsClickThrough(targetContent)) {
4497 *aStatus = nsEventStatus_eConsumeNoDefault;
4498 }
4499 }
4500 break;
4501#endif
4502
4503 default:
4504 break;
4505 }
4506
4507 // Reset target frame to null to avoid mistargeting after reentrant event
4508 mCurrentTarget = nullptr;
4509 mCurrentTargetContent = nullptr;
4510
4511 return ret;
4512}
4513
4514BrowserParent* EventStateManager::GetCrossProcessTarget() {
4515 return IMEStateManager::GetActiveBrowserParent();
4516}
4517
4518bool EventStateManager::IsTargetCrossProcess(WidgetGUIEvent* aEvent) {
4519 // Check to see if there is a focused, editable content in chrome,
4520 // in that case, do not forward IME events to content
4521 Element* focusedElement = GetFocusedElement();
4522 if (focusedElement && focusedElement->IsEditable()) {
4523 return false;
4524 }
4525 return IMEStateManager::GetActiveBrowserParent() != nullptr;
4526}
4527
4528void EventStateManager::NotifyDestroyPresContext(nsPresContext* aPresContext) {
4529 RefPtr<nsPresContext> presContext = aPresContext;
4530 if (presContext) {
4531 IMEStateManager::OnDestroyPresContext(*presContext);
4532 }
4533
4534 // Bug 70855: Presentation is going away, possibly for a reframe.
4535 // Reset the hover state so that if we're recreating the presentation,
4536 // we won't have the old hover state still set in the new presentation,
4537 // as if the new presentation is resized, a new element may be hovered.
4538 ResetHoverState();
4539
4540 mMouseEnterLeaveHelper = nullptr;
4541 mPointersEnterLeaveHelper.Clear();
4542 PointerEventHandler::NotifyDestroyPresContext(presContext);
4543}
4544
4545void EventStateManager::ResetHoverState() {
4546 if (mHoverContent) {
4547 SetContentState(nullptr, ElementState::HOVER);
4548 }
4549}
4550
4551void EventStateManager::SetPresContext(nsPresContext* aPresContext) {
4552 mPresContext = aPresContext;
4553}
4554
4555void EventStateManager::ClearFrameRefs(nsIFrame* aFrame) {
4556 if (aFrame && aFrame == mCurrentTarget) {
4557 mCurrentTargetContent = aFrame->GetContent();
4558 }
4559}
4560
4561struct CursorImage {
4562 gfx::IntPoint mHotspot;
4563 nsCOMPtr<imgIContainer> mContainer;
4564 ImageResolution mResolution;
4565 bool mEarlierCursorLoading = false;
4566};
4567
4568// Given the event that we're processing, and the computed cursor and hotspot,
4569// determine whether the custom CSS cursor should be blocked (that is, not
4570// honored).
4571//
4572// We will not honor it all of the following are true:
4573//
4574// * the size of the custom cursor is bigger than layout.cursor.block.max-size.
4575// * the bounds of the cursor would end up outside of the viewport of the
4576// top-level content document.
4577//
4578// This is done in order to prevent hijacking the cursor, see bug 1445844 and
4579// co.
4580static bool ShouldBlockCustomCursor(nsPresContext* aPresContext,
4581 WidgetEvent* aEvent,
4582 const CursorImage& aCursor) {
4583 int32_t width = 0;
4584 int32_t height = 0;
4585 aCursor.mContainer->GetWidth(&width);
4586 aCursor.mContainer->GetHeight(&height);
4587 aCursor.mResolution.ApplyTo(width, height);
4588
4589 int32_t maxSize = StaticPrefs::layout_cursor_block_max_size();
4590
4591 if (width <= maxSize && height <= maxSize) {
4592 return false;
4593 }
4594
4595 auto input = DOMIntersectionObserver::ComputeInput(*aPresContext->Document(),
4596 nullptr, nullptr);
4597
4598 if (!input.mRootFrame) {
4599 return false;
4600 }
4601
4602 nsPoint point = nsLayoutUtils::GetEventCoordinatesRelativeTo(
4603 aEvent, RelativeTo{input.mRootFrame});
4604
4605 // The cursor size won't be affected by our full zoom in the parent process,
4606 // so undo that before checking the rect.
4607 float zoom = aPresContext->GetFullZoom();
4608
4609 // Also adjust for accessibility cursor scaling factor.
4610 zoom /= LookAndFeel::GetFloat(LookAndFeel::FloatID::CursorScale, 1.0f);
4611
4612 nsSize size(CSSPixel::ToAppUnits(width / zoom),
4613 CSSPixel::ToAppUnits(height / zoom));
4614 nsPoint hotspot(
4615 CSSPixel::ToAppUnits(ViewAs<CSSPixel>(aCursor.mHotspot.x / zoom)),
4616 CSSPixel::ToAppUnits(ViewAs<CSSPixel>(aCursor.mHotspot.y / zoom)));
4617
4618 const nsRect cursorRect(point - hotspot, size);
4619 auto output = DOMIntersectionObserver::Intersect(input, cursorRect);
4620 return !output.mIntersectionRect ||
4621 !(*output.mIntersectionRect == cursorRect);
4622}
4623
4624static gfx::IntPoint ComputeHotspot(imgIContainer* aContainer,
4625 const Maybe<gfx::Point>& aHotspot) {
4626 MOZ_ASSERT(aContainer)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContainer)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aContainer))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aContainer", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4626); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContainer"
")"); do { *((volatile int*)__null) = 4626; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4627
4628 // css3-ui says to use the CSS-specified hotspot if present,
4629 // otherwise use the intrinsic hotspot, otherwise use the top left
4630 // corner.
4631 if (aHotspot) {
4632 int32_t imgWidth, imgHeight;
4633 aContainer->GetWidth(&imgWidth);
4634 aContainer->GetHeight(&imgHeight);
4635 auto hotspot = gfx::IntPoint::Round(*aHotspot);
4636 return {std::max(std::min(hotspot.x.value, imgWidth - 1), 0),
4637 std::max(std::min(hotspot.y.value, imgHeight - 1), 0)};
4638 }
4639
4640 gfx::IntPoint hotspot;
4641 aContainer->GetHotspotX(&hotspot.x.value);
4642 aContainer->GetHotspotY(&hotspot.y.value);
4643 return hotspot;
4644}
4645
4646static CursorImage ComputeCustomCursor(nsPresContext* aPresContext,
4647 WidgetEvent* aEvent,
4648 const nsIFrame& aFrame,
4649 const nsIFrame::Cursor& aCursor) {
4650 if (aCursor.mAllowCustomCursor == nsIFrame::AllowCustomCursorImage::No) {
4651 return {};
4652 }
4653 const ComputedStyle& style =
4654 aCursor.mStyle ? *aCursor.mStyle : *aFrame.Style();
4655
4656 // If we are falling back because any cursor before us is loading, let the
4657 // consumer know.
4658 bool loading = false;
4659 for (const auto& image : style.StyleUI()->Cursor().images.AsSpan()) {
4660 MOZ_ASSERT(image.image.IsImageRequestType(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(image.image.IsImageRequestType())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(image.image.IsImageRequestType
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("image.image.IsImageRequestType()" " (" "Cursor image should only parse url() types"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4661); AnnotateMozCrashReason("MOZ_ASSERT" "(" "image.image.IsImageRequestType()"
") (" "Cursor image should only parse url() types" ")"); do {
*((volatile int*)__null) = 4661; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
4661 "Cursor image should only parse url() types")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(image.image.IsImageRequestType())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(image.image.IsImageRequestType
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("image.image.IsImageRequestType()" " (" "Cursor image should only parse url() types"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4661); AnnotateMozCrashReason("MOZ_ASSERT" "(" "image.image.IsImageRequestType()"
") (" "Cursor image should only parse url() types" ")"); do {
*((volatile int*)__null) = 4661; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
4662 uint32_t status;
4663 imgRequestProxy* req = image.image.GetImageRequest();
4664 if (!req || NS_FAILED(req->GetImageStatus(&status))((bool)(__builtin_expect(!!(NS_FAILED_impl(req->GetImageStatus
(&status))), 0)))
) {
4665 continue;
4666 }
4667 if (!(status & imgIRequest::STATUS_LOAD_COMPLETE)) {
4668 loading = true;
4669 continue;
4670 }
4671 if (status & imgIRequest::STATUS_ERROR) {
4672 continue;
4673 }
4674 nsCOMPtr<imgIContainer> container;
4675 req->GetImage(getter_AddRefs(container));
4676 if (!container) {
4677 continue;
4678 }
4679 StyleImageOrientation orientation =
4680 aFrame.StyleVisibility()->UsedImageOrientation(req);
4681 container = nsLayoutUtils::OrientImage(container, orientation);
4682 Maybe<gfx::Point> specifiedHotspot =
4683 image.has_hotspot ? Some(gfx::Point{image.hotspot_x, image.hotspot_y})
4684 : Nothing();
4685 gfx::IntPoint hotspot = ComputeHotspot(container, specifiedHotspot);
4686 CursorImage result{hotspot, std::move(container),
4687 image.image.GetResolution(style), loading};
4688 if (ShouldBlockCustomCursor(aPresContext, aEvent, result)) {
4689 continue;
4690 }
4691 // This is the one we want!
4692 return result;
4693 }
4694 return {{}, nullptr, {}, loading};
4695}
4696
4697void EventStateManager::UpdateCursor(nsPresContext* aPresContext,
4698 WidgetMouseEvent* aEvent,
4699 nsIFrame* aTargetFrame,
4700 nsEventStatus* aStatus) {
4701 if (aTargetFrame && IsRemoteTarget(aTargetFrame->GetContent())) {
4702 return;
4703 }
4704
4705 auto cursor = StyleCursorKind::Default;
4706 nsCOMPtr<imgIContainer> container;
4707 ImageResolution resolution;
4708 Maybe<gfx::IntPoint> hotspot;
4709
4710 if (mHidingCursorWhileTyping && aEvent->IsReal()) {
4711 // Any non-synthetic mouse event makes us show the cursor again.
4712 mHidingCursorWhileTyping = false;
4713 }
4714
4715 if (mHidingCursorWhileTyping) {
4716 cursor = StyleCursorKind::None;
4717 } else if (mLockCursor != kInvalidCursorKind) {
4718 // If cursor is locked just use the locked one
4719 cursor = mLockCursor;
4720 } else if (aTargetFrame) {
4721 // If not locked, look for correct cursor
4722 nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(
4723 aEvent, RelativeTo{aTargetFrame});
4724 const nsIFrame::Cursor framecursor = aTargetFrame->GetCursor(pt);
4725 const CursorImage customCursor =
4726 ComputeCustomCursor(aPresContext, aEvent, *aTargetFrame, framecursor);
4727
4728 // If the current cursor is from the same frame, and it is now
4729 // loading some new image for the cursor, we should wait for a
4730 // while rather than taking its fallback cursor directly.
4731 if (customCursor.mEarlierCursorLoading &&
4732 gLastCursorSourceFrame == aTargetFrame &&
4733 TimeStamp::NowLoRes() - gLastCursorUpdateTime <
4734 TimeDuration::FromMilliseconds(kCursorLoadingTimeout)) {
4735 return;
4736 }
4737 cursor = framecursor.mCursor;
4738 container = std::move(customCursor.mContainer);
4739 resolution = customCursor.mResolution;
4740 hotspot = Some(customCursor.mHotspot);
4741 }
4742
4743 if (aTargetFrame) {
4744 if (cursor == StyleCursorKind::Pointer && IsSelectingLink(aTargetFrame)) {
4745 cursor = aTargetFrame->GetWritingMode().IsVertical()
4746 ? StyleCursorKind::VerticalText
4747 : StyleCursorKind::Text;
4748 }
4749 SetCursor(cursor, container, resolution, hotspot,
4750 aTargetFrame->GetNearestWidget(), false);
4751 gLastCursorSourceFrame = aTargetFrame;
4752 gLastCursorUpdateTime = TimeStamp::NowLoRes();
4753 }
4754
4755 if (mLockCursor != kInvalidCursorKind || StyleCursorKind::Auto != cursor) {
4756 *aStatus = nsEventStatus_eConsumeDoDefault;
4757 }
4758}
4759
4760void EventStateManager::ClearCachedWidgetCursor(nsIFrame* aTargetFrame) {
4761 if (!aTargetFrame) {
4762 return;
4763 }
4764 nsIWidget* aWidget = aTargetFrame->GetNearestWidget();
4765 if (!aWidget) {
4766 return;
4767 }
4768 aWidget->ClearCachedCursor();
4769}
4770
4771void EventStateManager::StartHidingCursorWhileTyping(nsIWidget* aWidget) {
4772 if (mHidingCursorWhileTyping || sCursorSettingManager != this) {
4773 return;
4774 }
4775 mHidingCursorWhileTyping = true;
4776 SetCursor(StyleCursorKind::None, nullptr, {}, {}, aWidget, false);
4777}
4778
4779nsresult EventStateManager::SetCursor(StyleCursorKind aCursor,
4780 imgIContainer* aContainer,
4781 const ImageResolution& aResolution,
4782 const Maybe<gfx::IntPoint>& aHotspot,
4783 nsIWidget* aWidget, bool aLockCursor) {
4784 EnsureDocument(mPresContext);
4785 NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(mDocument)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mDocument" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4785); return NS_ERROR_FAILURE; } } while (false)
;
4786 sCursorSettingManager = this;
4787
4788 NS_ENSURE_TRUE(aWidget, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(aWidget)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aWidget" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4788); return NS_ERROR_FAILURE; } } while (false)
;
4789 if (aLockCursor) {
4790 if (StyleCursorKind::Auto != aCursor) {
4791 mLockCursor = aCursor;
4792 } else {
4793 // If cursor style is set to auto we unlock the cursor again.
4794 mLockCursor = kInvalidCursorKind;
4795 }
4796 }
4797 nsCursor c;
4798 switch (aCursor) {
4799 case StyleCursorKind::Auto:
4800 case StyleCursorKind::Default:
4801 c = eCursor_standard;
4802 break;
4803 case StyleCursorKind::Pointer:
4804 c = eCursor_hyperlink;
4805 break;
4806 case StyleCursorKind::Crosshair:
4807 c = eCursor_crosshair;
4808 break;
4809 case StyleCursorKind::Move:
4810 c = eCursor_move;
4811 break;
4812 case StyleCursorKind::Text:
4813 c = eCursor_select;
4814 break;
4815 case StyleCursorKind::Wait:
4816 c = eCursor_wait;
4817 break;
4818 case StyleCursorKind::Help:
4819 c = eCursor_help;
4820 break;
4821 case StyleCursorKind::NResize:
4822 c = eCursor_n_resize;
4823 break;
4824 case StyleCursorKind::SResize:
4825 c = eCursor_s_resize;
4826 break;
4827 case StyleCursorKind::WResize:
4828 c = eCursor_w_resize;
4829 break;
4830 case StyleCursorKind::EResize:
4831 c = eCursor_e_resize;
4832 break;
4833 case StyleCursorKind::NwResize:
4834 c = eCursor_nw_resize;
4835 break;
4836 case StyleCursorKind::SeResize:
4837 c = eCursor_se_resize;
4838 break;
4839 case StyleCursorKind::NeResize:
4840 c = eCursor_ne_resize;
4841 break;
4842 case StyleCursorKind::SwResize:
4843 c = eCursor_sw_resize;
4844 break;
4845 case StyleCursorKind::Copy: // CSS3
4846 c = eCursor_copy;
4847 break;
4848 case StyleCursorKind::Alias:
4849 c = eCursor_alias;
4850 break;
4851 case StyleCursorKind::ContextMenu:
4852 c = eCursor_context_menu;
4853 break;
4854 case StyleCursorKind::Cell:
4855 c = eCursor_cell;
4856 break;
4857 case StyleCursorKind::Grab:
4858 c = eCursor_grab;
4859 break;
4860 case StyleCursorKind::Grabbing:
4861 c = eCursor_grabbing;
4862 break;
4863 case StyleCursorKind::Progress:
4864 c = eCursor_spinning;
4865 break;
4866 case StyleCursorKind::ZoomIn:
4867 c = eCursor_zoom_in;
4868 break;
4869 case StyleCursorKind::ZoomOut:
4870 c = eCursor_zoom_out;
4871 break;
4872 case StyleCursorKind::NotAllowed:
4873 c = eCursor_not_allowed;
4874 break;
4875 case StyleCursorKind::ColResize:
4876 c = eCursor_col_resize;
4877 break;
4878 case StyleCursorKind::RowResize:
4879 c = eCursor_row_resize;
4880 break;
4881 case StyleCursorKind::NoDrop:
4882 c = eCursor_no_drop;
4883 break;
4884 case StyleCursorKind::VerticalText:
4885 c = eCursor_vertical_text;
4886 break;
4887 case StyleCursorKind::AllScroll:
4888 c = eCursor_all_scroll;
4889 break;
4890 case StyleCursorKind::NeswResize:
4891 c = eCursor_nesw_resize;
4892 break;
4893 case StyleCursorKind::NwseResize:
4894 c = eCursor_nwse_resize;
4895 break;
4896 case StyleCursorKind::NsResize:
4897 c = eCursor_ns_resize;
4898 break;
4899 case StyleCursorKind::EwResize:
4900 c = eCursor_ew_resize;
4901 break;
4902 case StyleCursorKind::None:
4903 c = eCursor_none;
4904 break;
4905 default:
4906 MOZ_ASSERT_UNREACHABLE("Unknown cursor kind")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Unknown cursor kind" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4906); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unknown cursor kind" ")"); do { *
((volatile int*)__null) = 4906; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
4907 c = eCursor_standard;
4908 break;
4909 }
4910
4911 uint32_t x = aHotspot ? aHotspot->x.value : 0;
4912 uint32_t y = aHotspot ? aHotspot->y.value : 0;
4913 aWidget->SetCursor(nsIWidget::Cursor{c, aContainer, x, y, aResolution});
4914 return NS_OK;
4915}
4916
4917bool EventStateManager::CursorSettingManagerHasLockedCursor() {
4918 return sCursorSettingManager &&
4919 sCursorSettingManager->mLockCursor != kInvalidCursorKind;
4920}
4921
4922class MOZ_STACK_CLASS ESMEventCB : public EventDispatchingCallback {
4923 public:
4924 explicit ESMEventCB(nsIContent* aTarget) : mTarget(aTarget) {}
4925
4926 MOZ_CAN_RUN_SCRIPT
4927 void HandleEvent(EventChainPostVisitor& aVisitor) override {
4928 if (aVisitor.mPresContext) {
4929 nsIFrame* frame = aVisitor.mPresContext->GetPrimaryFrameFor(mTarget);
4930 if (frame) {
4931 frame->HandleEvent(aVisitor.mPresContext, aVisitor.mEvent->AsGUIEvent(),
4932 &aVisitor.mEventStatus);
4933 }
4934 }
4935 }
4936
4937 nsCOMPtr<nsIContent> mTarget;
4938};
4939
4940static UniquePtr<WidgetMouseEvent> CreateMouseOrPointerWidgetEvent(
4941 WidgetMouseEvent* aMouseEvent, EventMessage aMessage,
4942 EventTarget* aRelatedTarget) {
4943 // This method does not support creating a mouse/pointer button change event
4944 // because of no data about the changing state.
4945 MOZ_ASSERT(aMessage != eMouseDown)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage != eMouseDown)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage != eMouseDown))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aMessage != eMouseDown"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4945); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != eMouseDown"
")"); do { *((volatile int*)__null) = 4945; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4946 MOZ_ASSERT(aMessage != eMouseUp)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage != eMouseUp)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage != eMouseUp))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("aMessage != eMouseUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4946); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != eMouseUp"
")"); do { *((volatile int*)__null) = 4946; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4947 MOZ_ASSERT(aMessage != ePointerDown)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage != ePointerDown)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage != ePointerDown))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aMessage != ePointerDown"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4947); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != ePointerDown"
")"); do { *((volatile int*)__null) = 4947; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4948 MOZ_ASSERT(aMessage != ePointerUp)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage != ePointerUp)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage != ePointerUp))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("aMessage != ePointerUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4948); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage != ePointerUp"
")"); do { *((volatile int*)__null) = 4948; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4949 // This method is currently designed to create the following events.
4950 MOZ_ASSERT(aMessage == eMouseOver || aMessage == eMouseEnter ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4955); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4955; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4951 aMessage == eMouseOut || aMessage == eMouseLeave ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4955); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4955; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4952 aMessage == ePointerOver || aMessage == ePointerEnter ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4955); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4955; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4953 aMessage == ePointerOut || aMessage == ePointerLeave ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4955); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4955; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4954 aMessage == eMouseEnterIntoWidget ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4955); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4955; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4955 aMessage == eMouseExitFromWidget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseOver || aMessage == eMouseEnter ||
aMessage == eMouseOut || aMessage == eMouseLeave || aMessage
== ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut
|| aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseOver || aMessage
== eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave
|| aMessage == ePointerOver || aMessage == ePointerEnter || aMessage
== ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget
|| aMessage == eMouseExitFromWidget))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 4955); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseOver || aMessage == eMouseEnter || aMessage == eMouseOut || aMessage == eMouseLeave || aMessage == ePointerOver || aMessage == ePointerEnter || aMessage == ePointerOut || aMessage == ePointerLeave || aMessage == eMouseEnterIntoWidget || aMessage == eMouseExitFromWidget"
")"); do { *((volatile int*)__null) = 4955; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4956
4957 WidgetPointerEvent* sourcePointer = aMouseEvent->AsPointerEvent();
4958 UniquePtr<WidgetMouseEvent> newEvent;
4959 if (sourcePointer) {
4960 AUTO_PROFILER_LABEL("CreateMouseOrPointerWidgetEvent", OTHER)mozilla::AutoProfilerLabel raiiObject4960( "CreateMouseOrPointerWidgetEvent"
, nullptr, JS::ProfilingCategoryPair::OTHER)
;
4961
4962 WidgetPointerEvent* newPointerEvent = new WidgetPointerEvent(
4963 aMouseEvent->IsTrusted(), aMessage, aMouseEvent->mWidget);
4964 newPointerEvent->mIsPrimary = sourcePointer->mIsPrimary;
4965 newPointerEvent->mWidth = sourcePointer->mWidth;
4966 newPointerEvent->mHeight = sourcePointer->mHeight;
4967 newPointerEvent->mInputSource = sourcePointer->mInputSource;
4968
4969 newEvent = WrapUnique(newPointerEvent);
4970 } else {
4971 newEvent = MakeUnique<WidgetMouseEvent>(aMouseEvent->IsTrusted(), aMessage,
4972 aMouseEvent->mWidget,
4973 WidgetMouseEvent::eReal);
4974 }
4975
4976 // Inherit whether the event is synthesized by the test API or not.
4977 // Then, when the event is synthesized by a test API and handled in a remote
4978 // process, it won't be ignored. See PresShell::HandleEvent().
4979 newEvent->mFlags.mIsSynthesizedForTests =
4980 aMouseEvent->mFlags.mIsSynthesizedForTests;
4981
4982 newEvent->mRelatedTarget = aRelatedTarget;
4983 newEvent->mRefPoint = aMouseEvent->mRefPoint;
4984 newEvent->mModifiers = aMouseEvent->mModifiers;
4985 if (!aMouseEvent->mFlags.mDispatchedAtLeastOnce &&
4986 aMouseEvent->InputSourceSupportsHover()) {
4987 // If we synthesize a pointer event or a mouse event from another event
4988 // which changes a button state whose input soucre supports hover state and
4989 // the source event has not been dispatched yet, we should set to the button
4990 // state of the synthesizing event to previous one.
4991 // Note that we don't need to do this if the input source does not support
4992 // hover state because a WPT check the behavior (see below) and the other
4993 // browsers pass the test even though this is inconsistent behavior.
4994 newEvent->mButton =
4995 sourcePointer ? MouseButton::eNotPressed : MouseButton::ePrimary;
4996 if (aMouseEvent->IsPressingButton()) {
4997 // If the source event has not been dispatched into the DOM yet, we
4998 // need to remove the flag which is being pressed.
4999 newEvent->mButtons = static_cast<decltype(WidgetMouseEvent::mButtons)>(
5000 aMouseEvent->mButtons &
5001 ~MouseButtonsFlagToChange(
5002 static_cast<MouseButton>(aMouseEvent->mButton)));
5003 } else if (aMouseEvent->IsReleasingButton()) {
5004 // If the source event has not been dispatched into the DOM yet, we
5005 // need to add the flag which is being released.
5006 newEvent->mButtons = static_cast<decltype(WidgetMouseEvent::mButtons)>(
5007 aMouseEvent->mButtons |
5008 MouseButtonsFlagToChange(
5009 static_cast<MouseButton>(aMouseEvent->mButton)));
5010 } else {
5011 // The source event does not change the buttons state so that we can
5012 // set mButtons value as-is.
5013 newEvent->mButtons = aMouseEvent->mButtons;
5014 }
5015 // Adjust pressure if it does not matches with mButtons.
5016 // FIXME: We may use wrong pressure value if the source event has not been
5017 // dispatched into the DOM yet. However, fixing this requires to store the
5018 // last pressure value somewhere.
5019 if (newEvent->mButtons && aMouseEvent->mPressure == 0) {
5020 newEvent->mPressure = 0.5f;
5021 } else if (!newEvent->mButtons && aMouseEvent->mPressure != 0) {
5022 newEvent->mPressure = 0;
5023 } else {
5024 newEvent->mPressure = aMouseEvent->mPressure;
5025 }
5026 } else {
5027 // If the event has already been dispatched into the tree, web apps has
5028 // already handled the button state change, so the button state of the
5029 // source event has already synced.
5030 // If the input source does not have hover state, we don't need to modify
5031 // the state because the other browsers behave so and tested by
5032 // pointerevent_attributes_nohover_pointers.html even though this is
5033 // different expectation from
5034 // pointerevent_attributes_hoverable_pointers.html, but the other browsers
5035 // pass both of them.
5036 newEvent->mButton = aMouseEvent->mButton;
5037 newEvent->mButtons = aMouseEvent->mButtons;
5038 newEvent->mPressure = aMouseEvent->mPressure;
5039 }
5040
5041 newEvent->mInputSource = aMouseEvent->mInputSource;
5042 newEvent->pointerId = aMouseEvent->pointerId;
5043
5044 return newEvent;
5045}
5046
5047already_AddRefed<nsIWidget>
5048EventStateManager::DispatchMouseOrPointerBoundaryEvent(
5049 WidgetMouseEvent* aMouseEvent, EventMessage aMessage,
5050 nsIContent* aTargetContent, nsIContent* aRelatedContent) {
5051 MOZ_ASSERT(aMessage == eMouseEnter || aMessage == ePointerEnter ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseEnter || aMessage == ePointerEnter
|| aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage
== eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut
|| aMessage == ePointerOut)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseEnter || aMessage
== ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave
|| aMessage == eMouseOver || aMessage == ePointerOver || aMessage
== eMouseOut || aMessage == ePointerOut))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5054); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5054; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5052 aMessage == eMouseLeave || aMessage == ePointerLeave ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseEnter || aMessage == ePointerEnter
|| aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage
== eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut
|| aMessage == ePointerOut)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseEnter || aMessage
== ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave
|| aMessage == eMouseOver || aMessage == ePointerOver || aMessage
== eMouseOut || aMessage == ePointerOut))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5054); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5054; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5053 aMessage == eMouseOver || aMessage == ePointerOver ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseEnter || aMessage == ePointerEnter
|| aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage
== eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut
|| aMessage == ePointerOut)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseEnter || aMessage
== ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave
|| aMessage == eMouseOver || aMessage == ePointerOver || aMessage
== eMouseOut || aMessage == ePointerOut))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5054); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5054; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5054 aMessage == eMouseOut || aMessage == ePointerOut)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eMouseEnter || aMessage == ePointerEnter
|| aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage
== eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut
|| aMessage == ePointerOut)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMessage == eMouseEnter || aMessage
== ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave
|| aMessage == eMouseOver || aMessage == ePointerOver || aMessage
== eMouseOut || aMessage == ePointerOut))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5054); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eMouseEnter || aMessage == ePointerEnter || aMessage == eMouseLeave || aMessage == ePointerLeave || aMessage == eMouseOver || aMessage == ePointerOver || aMessage == eMouseOut || aMessage == ePointerOut"
")"); do { *((volatile int*)__null) = 5054; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5055
5056 // https://w3c.github.io/pointerlock/#dom-element-requestpointerlock
5057 // "[Once in the locked state...E]vents that require the concept
5058 // of a mouse cursor must not be dispatched (for example: mouseover,
5059 // mouseout...).
5060 // XXXedgar should we also block pointer events?
5061 if (PointerLockManager::IsLocked() &&
5062 (aMessage == eMouseLeave || aMessage == eMouseEnter ||
5063 aMessage == eMouseOver || aMessage == eMouseOut)) {
5064 mCurrentTargetContent = nullptr;
5065 nsCOMPtr<Element> pointerLockedElement =
5066 PointerLockManager::GetLockedElement();
5067 if (!pointerLockedElement) {
5068 NS_WARNING("Should have pointer locked element, but didn't.")NS_DebugBreak(NS_DEBUG_WARNING, "Should have pointer locked element, but didn't."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5068)
;
5069 return nullptr;
5070 }
5071 nsIFrame* const pointerLockedFrame =
5072 mPresContext->GetPrimaryFrameFor(pointerLockedElement);
5073 if (NS_WARN_IF(!pointerLockedFrame)NS_warn_if_impl(!pointerLockedFrame, "!pointerLockedFrame", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5073)
) {
5074 return nullptr;
5075 }
5076 return do_AddRef(pointerLockedFrame->GetNearestWidget());
5077 }
5078
5079 mCurrentTargetContent = nullptr;
5080
5081 if (!aTargetContent) {
5082 return nullptr;
5083 }
5084
5085 // Store the widget before dispatching the event because some event listeners
5086 // of the dispatching event may cause reframe the target or remove the target
5087 // from the tree.
5088 nsCOMPtr<nsIWidget> targetWidget;
5089 if (nsIFrame* const targetFrame =
5090 mPresContext->GetPrimaryFrameFor(aTargetContent)) {
5091 targetWidget = targetFrame->GetNearestWidget();
5092 }
5093
5094 nsCOMPtr<nsIContent> targetContent = aTargetContent;
5095 nsCOMPtr<nsIContent> relatedContent = aRelatedContent;
5096
5097 UniquePtr<WidgetMouseEvent> dispatchEvent =
5098 CreateMouseOrPointerWidgetEvent(aMouseEvent, aMessage, relatedContent);
5099
5100 AutoWeakFrame previousTarget = mCurrentTarget;
5101 mCurrentTargetContent = targetContent;
5102
5103 nsEventStatus status = nsEventStatus_eIgnore;
5104 ESMEventCB callback(targetContent);
5105 RefPtr<nsPresContext> presContext = mPresContext;
5106 EventDispatcher::Dispatch(targetContent, presContext, dispatchEvent.get(),
5107 nullptr, &status, &callback);
5108
5109 if (mPresContext) {
5110 // If we are entering/leaving remote content, dispatch a mouse enter/exit
5111 // event to the remote frame.
5112 if (IsTopLevelRemoteTarget(targetContent)) {
5113 if (aMessage == eMouseOut) {
5114 // For remote content, send a puppet widget mouse exit event.
5115 UniquePtr<WidgetMouseEvent> remoteEvent =
5116 CreateMouseOrPointerWidgetEvent(aMouseEvent, eMouseExitFromWidget,
5117 relatedContent);
5118 remoteEvent->mExitFrom = Some(WidgetMouseEvent::ePuppet);
5119
5120 // mCurrentTarget is set to the new target, so we must reset it to the
5121 // old target and then dispatch a cross-process event. (mCurrentTarget
5122 // will be set back below.) HandleCrossProcessEvent will query for the
5123 // proper target via GetEventTarget which will return mCurrentTarget.
5124 mCurrentTarget = mPresContext->GetPrimaryFrameFor(targetContent);
5125 HandleCrossProcessEvent(remoteEvent.get(), &status);
5126 } else if (aMessage == eMouseOver) {
5127 UniquePtr<WidgetMouseEvent> remoteEvent =
5128 CreateMouseOrPointerWidgetEvent(aMouseEvent, eMouseEnterIntoWidget,
5129 relatedContent);
5130 HandleCrossProcessEvent(remoteEvent.get(), &status);
5131 }
5132 }
5133 }
5134
5135 mCurrentTargetContent = nullptr;
5136 mCurrentTarget = previousTarget;
5137
5138 return targetWidget.forget();
5139}
5140
5141static nsIContent* FindCommonAncestor(nsIContent* aNode1, nsIContent* aNode2) {
5142 if (!aNode1 || !aNode2) {
5143 return nullptr;
5144 }
5145 return nsContentUtils::GetCommonFlattenedTreeAncestor(aNode1, aNode2);
5146}
5147
5148class EnterLeaveDispatcher {
5149 public:
5150 EnterLeaveDispatcher(EventStateManager* aESM, nsIContent* aTarget,
5151 nsIContent* aRelatedTarget,
5152 WidgetMouseEvent* aMouseEvent,
5153 EventMessage aEventMessage)
5154 : mESM(aESM), mMouseEvent(aMouseEvent), mEventMessage(aEventMessage) {
5155 nsPIDOMWindowInner* win =
5156 aTarget ? aTarget->OwnerDoc()->GetInnerWindow() : nullptr;
5157 if (aMouseEvent->AsPointerEvent()
5158 ? win && win->HasPointerEnterLeaveEventListeners()
5159 : win && win->HasMouseEnterLeaveEventListeners()) {
5160 mRelatedTarget =
5161 aRelatedTarget ? aRelatedTarget->FindFirstNonChromeOnlyAccessContent()
5162 : nullptr;
5163 nsINode* commonParent = FindCommonAncestor(aTarget, aRelatedTarget);
5164 nsIContent* current = aTarget;
5165 // Note, it is ok if commonParent is null!
5166 while (current && current != commonParent) {
5167 if (!current->ChromeOnlyAccess()) {
5168 mTargets.AppendObject(current);
5169 }
5170 // mouseenter/leave is fired only on elements.
5171 current = current->GetFlattenedTreeParent();
5172 }
5173 }
5174 }
5175
5176 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230)
5177 MOZ_CAN_RUN_SCRIPT_BOUNDARY void Dispatch() {
5178 if (mEventMessage == eMouseEnter || mEventMessage == ePointerEnter) {
5179 for (int32_t i = mTargets.Count() - 1; i >= 0; --i) {
5180 nsCOMPtr<nsIWidget> widget = mESM->DispatchMouseOrPointerBoundaryEvent(
5181 mMouseEvent, mEventMessage, MOZ_KnownLive(mTargets[i])(mTargets[i]),
5182 mRelatedTarget);
5183 }
5184 } else {
5185 for (int32_t i = 0; i < mTargets.Count(); ++i) {
5186 nsCOMPtr<nsIWidget> widget = mESM->DispatchMouseOrPointerBoundaryEvent(
5187 mMouseEvent, mEventMessage, MOZ_KnownLive(mTargets[i])(mTargets[i]),
5188 mRelatedTarget);
5189 }
5190 }
5191 }
5192
5193 // Nothing overwrites anything after constructor. Please remove MOZ_KnownLive
5194 // and MOZ_KNOWN_LIVE if anything marked as such becomes mutable.
5195 const RefPtr<EventStateManager> mESM;
5196 nsCOMArray<nsIContent> mTargets;
5197 MOZ_KNOWN_LIVE nsCOMPtr<nsIContent> mRelatedTarget;
5198 WidgetMouseEvent* mMouseEvent;
5199 EventMessage mEventMessage;
5200};
5201
5202void EventStateManager::NotifyMouseOut(WidgetMouseEvent* aMouseEvent,
5203 nsIContent* aMovingInto) {
5204 const bool isPointer = aMouseEvent->mClass == ePointerEventClass;
5205 LogModule* const logModule =
5206 isPointer ? sPointerBoundaryLog : sMouseBoundaryLog;
5207
5208 RefPtr<OverOutElementsWrapper> wrapper = GetWrapperByEventID(aMouseEvent);
5209
5210 // If there is no deepest "leave" event target, that means the last "over"
5211 // target has already been removed from the tree. Therefore, checking only
5212 // the "leave" event target is enough.
5213 if (!wrapper || !wrapper->GetDeepestLeaveEventTarget()) {
5214 return;
5215 }
5216 // Before firing "out" and/or "leave" events, check for recursion
5217 if (wrapper->IsDispatchingOutEventOnLastOverEventTarget()) {
5218 return;
5219 }
5220
5221 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOut: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5222 ("NotifyMouseOut: the source event is %s (IsReal()=%s)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOut: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5223 ToChar(aMouseEvent->mMessage),do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOut: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5224 aMouseEvent->IsReal() ? "true" : "false"))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOut: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
;
5225
5226 // XXX If a content node is a container of remove content, it should be
5227 // replaced with them and its children should not be visible. Therefore,
5228 // if the deepest "enter" target is not the last "over" target, i.e., the
5229 // last "over" target has been removed from the DOM tree, it means that the
5230 // child/descendant was not replaced by remote content. So,
5231 // wrapper->GetOutEventTaget() may be enough here.
5232 if (RefPtr<nsFrameLoaderOwner> flo =
5233 do_QueryObject(wrapper->GetDeepestLeaveEventTarget())) {
5234 if (BrowsingContext* bc = flo->GetExtantBrowsingContext()) {
5235 if (nsIDocShell* docshell = bc->GetDocShell()) {
5236 if (RefPtr<nsPresContext> presContext = docshell->GetPresContext()) {
5237 EventStateManager* kidESM = presContext->EventStateManager();
5238 // Not moving into any element in this subdocument
5239 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying child EventStateManager (%p) of \"out\" "
"event...", kidESM); } } while (0)
5240 ("Notifying child EventStateManager (%p) of \"out\" "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying child EventStateManager (%p) of \"out\" "
"event...", kidESM); } } while (0)
5241 "event...",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying child EventStateManager (%p) of \"out\" "
"event...", kidESM); } } while (0)
5242 kidESM))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying child EventStateManager (%p) of \"out\" "
"event...", kidESM); } } while (0)
;
5243 kidESM->NotifyMouseOut(aMouseEvent, nullptr);
5244 }
5245 }
5246 }
5247 }
5248 // That could have caused DOM events which could wreak havoc. Reverify
5249 // things and be careful.
5250 if (!wrapper->GetDeepestLeaveEventTarget()) {
5251 return;
5252 }
5253
5254 wrapper->WillDispatchOutAndOrLeaveEvent();
5255
5256 // Don't touch hover state if aMovingInto is non-null. Caller will update
5257 // hover state itself, and we have optimizations for hover switching between
5258 // two nearby elements both deep in the DOM tree that would be defeated by
5259 // switching the hover state to null here.
5260 if (!aMovingInto && !isPointer) {
5261 // Unset :hover
5262 SetContentState(nullptr, ElementState::HOVER);
5263 }
5264
5265 EnterLeaveDispatcher leaveDispatcher(
5266 this, wrapper->GetDeepestLeaveEventTarget(), aMovingInto, aMouseEvent,
5267 isPointer ? ePointerLeave : eMouseLeave);
5268
5269 // "out" events hould be fired only when the deepest "leave" event target
5270 // is the last "over" event target.
5271 if (nsCOMPtr<nsIContent> outEventTarget = wrapper->GetOutEventTarget()) {
5272 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
5273 ("Dispatching %s event to %s (%p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
5274 isPointer ? "ePointerOut" : "eMouseOut",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
5275 outEventTarget ? ToString(*outEventTarget).c_str() : "nullptr",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
5276 outEventTarget.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOut" : "eMouseOut", outEventTarget ? ToString(*outEventTarget
).c_str() : "nullptr", outEventTarget.get()); } } while (0)
;
5277 nsCOMPtr<nsIWidget> widget = DispatchMouseOrPointerBoundaryEvent(
5278 aMouseEvent, isPointer ? ePointerOut : eMouseOut, outEventTarget,
5279 aMovingInto);
5280 }
5281
5282 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5283 ("Dispatching %s event to %s (%p) and its ancestors",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5284 isPointer ? "ePointerLeave" : "eMouseLeave",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5285 wrapper->GetDeepestLeaveEventTarget()do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5286 ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str()do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5287 : "nullptr",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
5288 wrapper->GetDeepestLeaveEventTarget()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerLeave" : "eMouseLeave", wrapper->GetDeepestLeaveEventTarget
() ? ToString(*wrapper->GetDeepestLeaveEventTarget()).c_str
() : "nullptr", wrapper->GetDeepestLeaveEventTarget()); } }
while (0)
;
5289 leaveDispatcher.Dispatch();
5290
5291 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"out\" and/or \"leave\" events"
); } } while (0)
5292 ("Dispatched \"out\" and/or \"leave\" events"))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"out\" and/or \"leave\" events"
); } } while (0)
;
5293 wrapper->DidDispatchOutAndOrLeaveEvent();
5294}
5295
5296void EventStateManager::RecomputeMouseEnterStateForRemoteFrame(
5297 Element& aElement) {
5298 if (!mMouseEnterLeaveHelper ||
5299 mMouseEnterLeaveHelper->GetDeepestLeaveEventTarget() != &aElement) {
5300 return;
5301 }
5302
5303 if (BrowserParent* remote = BrowserParent::GetFrom(&aElement)) {
5304 remote->MouseEnterIntoWidget();
5305 }
5306}
5307
5308void EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
5309 nsIContent* aContent) {
5310 NS_ASSERTION(aContent, "Mouse must be over something")do { if (!(aContent)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Mouse must be over something"
, "aContent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5310); MOZ_PretendNoReturn(); } } while (0)
;
5311
5312 const bool isPointer = aMouseEvent->mClass == ePointerEventClass;
5313 LogModule* const logModule =
5314 isPointer ? sPointerBoundaryLog : sMouseBoundaryLog;
5315
5316 RefPtr<OverOutElementsWrapper> wrapper = GetWrapperByEventID(aMouseEvent);
5317
5318 // If we have next "out" event target and it's the new "over" target, we don't
5319 // need to dispatch "out" nor "enter" event.
5320 if (!wrapper || aContent == wrapper->GetOutEventTarget()) {
5321 return;
5322 }
5323
5324 // Before firing "over" and "enter" events, check for recursion
5325 if (wrapper->IsDispatchingOverEventOn(aContent)) {
5326 return;
5327 }
5328
5329 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOver: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5330 ("NotifyMouseOver: the source event is %s (IsReal()=%s)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOver: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5331 ToChar(aMouseEvent->mMessage),do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOver: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
5332 aMouseEvent->IsReal() ? "true" : "false"))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "NotifyMouseOver: the source event is %s (IsReal()=%s)"
, ToChar(aMouseEvent->mMessage), aMouseEvent->IsReal() ?
"true" : "false"); } } while (0)
;
5333
5334 // Check to see if we're a subdocument and if so update the parent
5335 // document's ESM state to indicate that the mouse is over the
5336 // content associated with our subdocument.
5337 EnsureDocument(mPresContext);
5338 if (Document* parentDoc = mDocument->GetInProcessParentDocument()) {
5339 if (nsCOMPtr<nsIContent> docContent = mDocument->GetEmbedderElement()) {
5340 if (PresShell* parentPresShell = parentDoc->GetPresShell()) {
5341 RefPtr<EventStateManager> parentESM =
5342 parentPresShell->GetPresContext()->EventStateManager();
5343 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying parent EventStateManager (%p) of \"over\" "
"event...", parentESM.get()); } } while (0)
5344 ("Notifying parent EventStateManager (%p) of \"over\" "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying parent EventStateManager (%p) of \"over\" "
"event...", parentESM.get()); } } while (0)
5345 "event...",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying parent EventStateManager (%p) of \"over\" "
"event...", parentESM.get()); } } while (0)
5346 parentESM.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Notifying parent EventStateManager (%p) of \"over\" "
"event...", parentESM.get()); } } while (0)
;
5347 parentESM->NotifyMouseOver(aMouseEvent, docContent);
5348 }
5349 }
5350 }
5351 // Firing the DOM event in the parent document could cause all kinds
5352 // of havoc. Reverify and take care.
5353 if (aContent == wrapper->GetOutEventTarget()) {
5354 return;
5355 }
5356
5357 // Remember the deepest leave event target as the related content for the
5358 // DispatchMouseOrPointerBoundaryEvent() call below, since NotifyMouseOut()
5359 // resets it, bug 298477.
5360 nsCOMPtr<nsIContent> deepestLeaveEventTarget =
5361 wrapper->GetDeepestLeaveEventTarget();
5362
5363 EnterLeaveDispatcher enterDispatcher(this, aContent, deepestLeaveEventTarget,
5364 aMouseEvent,
5365 isPointer ? ePointerEnter : eMouseEnter);
5366
5367 if (!isPointer) {
5368 SetContentState(aContent, ElementState::HOVER);
5369 }
5370
5371 NotifyMouseOut(aMouseEvent, aContent);
5372
5373 wrapper->WillDispatchOverAndEnterEvent(aContent);
5374
5375 // Fire mouseover
5376 // XXX If aContent has already been removed from the DOM tree, what should we
5377 // do? At least, dispatching `mouseover` on it is odd.
5378 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOver" : "eMouseOver", aContent ? ToString(*aContent
).c_str() : "nullptr", aContent); } } while (0)
5379 ("Dispatching %s event to %s (%p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOver" : "eMouseOver", aContent ? ToString(*aContent
).c_str() : "nullptr", aContent); } } while (0)
5380 isPointer ? "ePointerOver" : "eMouseOver",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOver" : "eMouseOver", aContent ? ToString(*aContent
).c_str() : "nullptr", aContent); } } while (0)
5381 aContent ? ToString(*aContent).c_str() : "nullptr", aContent))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p)", isPointer
? "ePointerOver" : "eMouseOver", aContent ? ToString(*aContent
).c_str() : "nullptr", aContent); } } while (0)
;
5382 nsCOMPtr<nsIWidget> targetWidget = DispatchMouseOrPointerBoundaryEvent(
5383 aMouseEvent, isPointer ? ePointerOver : eMouseOver, aContent,
5384 deepestLeaveEventTarget);
5385
5386 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerEnter" : "eMouseEnter", aContent ? ToString
(*aContent).c_str() : "nullptr", aContent); } } while (0)
5387 ("Dispatching %s event to %s (%p) and its ancestors",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerEnter" : "eMouseEnter", aContent ? ToString
(*aContent).c_str() : "nullptr", aContent); } } while (0)
5388 isPointer ? "ePointerEnter" : "eMouseEnter",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerEnter" : "eMouseEnter", aContent ? ToString
(*aContent).c_str() : "nullptr", aContent); } } while (0)
5389 aContent ? ToString(*aContent).c_str() : "nullptr", aContent))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatching %s event to %s (%p) and its ancestors"
, isPointer ? "ePointerEnter" : "eMouseEnter", aContent ? ToString
(*aContent).c_str() : "nullptr", aContent); } } while (0)
;
5390 enterDispatcher.Dispatch();
5391
5392 MOZ_LOG(logModule, LogLevel::Info,do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"over\" and \"enter\" events (the original \"over\" "
"event target was in the document %p, and now in %p)", aContent
->GetComposedDoc(), mDocument.get()); } } while (0)
5393 ("Dispatched \"over\" and \"enter\" events (the original \"over\" "do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"over\" and \"enter\" events (the original \"over\" "
"event target was in the document %p, and now in %p)", aContent
->GetComposedDoc(), mDocument.get()); } } while (0)
5394 "event target was in the document %p, and now in %p)",do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"over\" and \"enter\" events (the original \"over\" "
"event target was in the document %p, and now in %p)", aContent
->GetComposedDoc(), mDocument.get()); } } while (0)
5395 aContent->GetComposedDoc(), mDocument.get()))do { const ::mozilla::LogModule* moz_real_module = logModule;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Info)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Info, "Dispatched \"over\" and \"enter\" events (the original \"over\" "
"event target was in the document %p, and now in %p)", aContent
->GetComposedDoc(), mDocument.get()); } } while (0)
;
5396 wrapper->DidDispatchOverAndEnterEvent(
5397 aContent->GetComposedDoc() == mDocument ? aContent : nullptr,
5398 targetWidget);
5399}
5400
5401// Returns the center point of the window's client area. This is
5402// in widget coordinates, i.e. relative to the widget's top-left
5403// corner, not in screen coordinates, the same units that UIEvent::
5404// refpoint is in. It may not be the exact center of the window if
5405// the platform requires rounding the coordinate.
5406static LayoutDeviceIntPoint GetWindowClientRectCenter(nsIWidget* aWidget) {
5407 NS_ENSURE_TRUE(aWidget, LayoutDeviceIntPoint(0, 0))do { if ((__builtin_expect(!!(!(aWidget)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aWidget" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5407); return LayoutDeviceIntPoint(0, 0); } } while (false)
;
5408
5409 LayoutDeviceIntRect rect = aWidget->GetClientBounds();
5410 LayoutDeviceIntPoint point(rect.width / 2, rect.height / 2);
5411 int32_t round = aWidget->RoundsWidgetCoordinatesTo();
5412 point.x = point.x / round * round;
5413 point.y = point.y / round * round;
5414 return point;
5415}
5416
5417void EventStateManager::GeneratePointerEnterExit(EventMessage aMessage,
5418 WidgetMouseEvent* aEvent) {
5419 WidgetPointerEvent pointerEvent(*aEvent);
5420 pointerEvent.mMessage = aMessage;
5421 GenerateMouseEnterExit(&pointerEvent);
5422}
5423
5424/* static */
5425void EventStateManager::UpdateLastRefPointOfMouseEvent(
5426 WidgetMouseEvent* aMouseEvent) {
5427 if (aMouseEvent->mMessage != eMouseMove &&
5428 aMouseEvent->mMessage != ePointerMove) {
5429 return;
5430 }
5431
5432 // Mouse movement is reported on the MouseEvent.movement{X,Y} fields.
5433 // Movement is calculated in UIEvent::GetMovementPoint() as:
5434 // previous_mousemove_mRefPoint - current_mousemove_mRefPoint.
5435 if (PointerLockManager::IsLocked() && aMouseEvent->mWidget) {
5436 // The pointer is locked. If the pointer is not located at the center of
5437 // the window, dispatch a synthetic mousemove to return the pointer there.
5438 // Doing this between "real" pointer moves gives the impression that the
5439 // (locked) pointer can continue moving and won't stop at the screen
5440 // boundary. We cancel the synthetic event so that we don't end up
5441 // dispatching the centering move event to content.
5442 aMouseEvent->mLastRefPoint =
5443 GetWindowClientRectCenter(aMouseEvent->mWidget);
5444
5445 } else if (sLastRefPoint == kInvalidRefPoint) {
5446 // We don't have a valid previous mousemove mRefPoint. This is either
5447 // the first move we've encountered, or the mouse has just re-entered
5448 // the application window. We should report (0,0) movement for this
5449 // case, so make the current and previous mRefPoints the same.
5450 aMouseEvent->mLastRefPoint = aMouseEvent->mRefPoint;
5451 } else {
5452 aMouseEvent->mLastRefPoint = sLastRefPoint;
5453 }
5454}
5455
5456/* static */
5457void EventStateManager::ResetPointerToWindowCenterWhilePointerLocked(
5458 WidgetMouseEvent* aMouseEvent) {
5459 MOZ_ASSERT(PointerLockManager::IsLocked())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(PointerLockManager::IsLocked())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(PointerLockManager::IsLocked
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("PointerLockManager::IsLocked()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5459); AnnotateMozCrashReason("MOZ_ASSERT" "(" "PointerLockManager::IsLocked()"
")"); do { *((volatile int*)__null) = 5459; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5460 if ((aMouseEvent->mMessage != eMouseMove &&
5461 aMouseEvent->mMessage != ePointerMove) ||
5462 !aMouseEvent->mWidget) {
5463 return;
5464 }
5465
5466 // We generate pointermove from mousemove event, so only synthesize native
5467 // mouse move and update sSynthCenteringPoint by mousemove event.
5468 bool updateSynthCenteringPoint = aMouseEvent->mMessage == eMouseMove;
5469
5470 // The pointer is locked. If the pointer is not located at the center of
5471 // the window, dispatch a synthetic mousemove to return the pointer there.
5472 // Doing this between "real" pointer moves gives the impression that the
5473 // (locked) pointer can continue moving and won't stop at the screen
5474 // boundary. We cancel the synthetic event so that we don't end up
5475 // dispatching the centering move event to content.
5476 LayoutDeviceIntPoint center = GetWindowClientRectCenter(aMouseEvent->mWidget);
5477
5478 if (aMouseEvent->mRefPoint != center && updateSynthCenteringPoint) {
5479 // Mouse move doesn't finish at the center of the window. Dispatch a
5480 // synthetic native mouse event to move the pointer back to the center
5481 // of the window, to faciliate more movement. But first, record that
5482 // we've dispatched a synthetic mouse movement, so we can cancel it
5483 // in the other branch here.
5484 sSynthCenteringPoint = center;
5485 // XXX Once we fix XXX comments in SetPointerLock about this API, we could
5486 // restrict that this API works only in the automation mode or in the
5487 // pointer locked situation.
5488 aMouseEvent->mWidget->SynthesizeNativeMouseMove(
5489 center + aMouseEvent->mWidget->WidgetToScreenOffset(), nullptr);
5490 } else if (aMouseEvent->mRefPoint == sSynthCenteringPoint) {
5491 // This is the "synthetic native" event we dispatched to re-center the
5492 // pointer. Cancel it so we don't expose the centering move to content.
5493 aMouseEvent->StopPropagation();
5494 // Clear sSynthCenteringPoint so we don't cancel other events
5495 // targeted at the center.
5496 if (updateSynthCenteringPoint) {
5497 sSynthCenteringPoint = kInvalidRefPoint;
5498 }
5499 }
5500}
5501
5502/* static */
5503void EventStateManager::UpdateLastPointerPosition(
5504 WidgetMouseEvent* aMouseEvent) {
5505 if (aMouseEvent->mMessage != eMouseMove) {
5506 return;
5507 }
5508 sLastRefPoint = aMouseEvent->mRefPoint;
5509}
5510
5511void EventStateManager::GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent) {
5512 EnsureDocument(mPresContext);
5513 if (!mDocument) return;
5514
5515 // Hold onto old target content through the event and reset after.
5516 nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
5517
5518 switch (aMouseEvent->mMessage) {
5519 case eMouseMove:
5520 case ePointerMove:
5521 case ePointerDown:
5522 case ePointerGotCapture: {
5523 // Get the target content target (mousemove target == mouseover target)
5524 nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
5525 if (!targetElement) {
5526 // We're always over the document root, even if we're only
5527 // over dead space in a page (whose frame is not associated with
5528 // any content) or in print preview dead space
5529 targetElement = mDocument->GetRootElement();
5530 }
5531 if (targetElement) {
5532 NotifyMouseOver(aMouseEvent, targetElement);
5533 }
5534 break;
5535 }
5536 case ePointerUp: {
5537 if (!StaticPrefs::
5538 dom_events_mouse_pointer_boundary_keep_enter_targets_after_over_target_removed()) {
5539 // In the legacy mode, we should do nothing if the event has not been
5540 // dispatched yet (i.e., called by PreHandleEvent).
5541 // On the other hand, if the event was dispatched (i.e., called by
5542 // PostEventHandler), we need to dispatch "pointerout" and
5543 // "pointerleave" events because the pointer will be removed
5544 // (invalidated) by the "pointerup" operation.
5545 if (!aMouseEvent->mFlags.mDispatchedAtLeastOnce) {
5546 break;
5547 }
5548 MOZ_ASSERT(!aMouseEvent->InputSourceSupportsHover())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aMouseEvent->InputSourceSupportsHover())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aMouseEvent->InputSourceSupportsHover()))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!aMouseEvent->InputSourceSupportsHover()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5548); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aMouseEvent->InputSourceSupportsHover()"
")"); do { *((volatile int*)__null) = 5548; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5549 // Get the target content target (pointermove target == pointerover
5550 // target)
5551 nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
5552 if (!targetElement) {
5553 // We're always over the document root, even if we're only
5554 // over dead space in a page (whose frame is not associated with
5555 // any content) or in print preview dead space
5556 targetElement = mDocument->GetRootElement();
5557 }
5558 if (targetElement) {
5559 // XXX It's odd to override the `pointerout` event target with the
5560 // content under the pointer or something because it may have never
5561 // received `pointerover` event. I think that this was required for
5562 // digitizer which supports hover state (bug 985511). However, this
5563 // is now not called at ePointerUp if the device supports hover.
5564 RefPtr<OverOutElementsWrapper> helper =
5565 GetWrapperByEventID(aMouseEvent);
5566 if (helper) {
5567 helper->OverrideOverEventTarget(targetElement);
5568 }
5569 NotifyMouseOut(aMouseEvent, nullptr);
5570 }
5571 break;
5572 }
5573
5574 if (aMouseEvent->mFlags.mDispatchedAtLeastOnce) {
5575 // If we've already dispatched the pointerup event caused by
5576 // non-hoverable input device like touch, we need to synthesize
5577 // pointerout and pointerleave events because the poiner is valid only
5578 // while it's "down".
5579 if (!aMouseEvent->InputSourceSupportsHover()) {
5580 NotifyMouseOut(aMouseEvent, nullptr);
5581 }
5582 break;
5583 }
5584
5585 // If we're going to dispatch the pointerup event and the element under
5586 // the pointer is changed from the previous pointer event dispatching, we
5587 // need to dispatch pointer boundary events. If the pointing device is
5588 // hoverable, we always need to do it. Otherwise, an element captures the
5589 // pointer by default. If so, we don't need the boundary events, but if
5590 // the capture has already been released, e.g., by the capturing element
5591 // is removed, we need to dispatch the pointer boundary event the same
5592 // way as with hoverable pointer.
5593 if (aMouseEvent->InputSourceSupportsHover() ||
5594 !PointerEventHandler::GetPointerCapturingElement(
5595 aMouseEvent->pointerId)) {
5596 nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
5597 if (!targetElement) {
5598 targetElement = mDocument->GetRootElement();
5599 }
5600 if (targetElement) {
5601 NotifyMouseOver(aMouseEvent, targetElement);
5602 }
5603 break;
5604 }
5605 break;
5606 }
5607 case ePointerLeave:
5608 case ePointerCancel:
5609 case eMouseExitFromWidget: {
5610 // This is actually the window mouse exit or pointer leave event. We're
5611 // not moving into any new element.
5612
5613 RefPtr<OverOutElementsWrapper> helper = GetWrapperByEventID(aMouseEvent);
5614 if (helper) {
5615 nsCOMPtr<nsIWidget> lastOverWidget = helper->GetLastOverWidget();
5616 if (lastOverWidget &&
5617 nsContentUtils::GetTopLevelWidget(aMouseEvent->mWidget) !=
5618 nsContentUtils::GetTopLevelWidget(lastOverWidget)) {
5619 // the Mouse/PointerOut event widget doesn't have same top widget with
5620 // the last over event target, it's a spurious event for the frame for
5621 // the target.
5622 break;
5623 }
5624 }
5625
5626 // Reset sLastRefPoint, so that we'll know not to report any
5627 // movement the next time we re-enter the window.
5628 sLastRefPoint = kInvalidRefPoint;
5629
5630 NotifyMouseOut(aMouseEvent, nullptr);
5631 break;
5632 }
5633 default:
5634 break;
5635 }
5636
5637 // reset mCurretTargetContent to what it was
5638 mCurrentTargetContent = targetBeforeEvent;
5639}
5640
5641OverOutElementsWrapper* EventStateManager::GetWrapperByEventID(
5642 WidgetMouseEvent* aEvent) {
5643 WidgetPointerEvent* pointer = aEvent->AsPointerEvent();
5644 if (!pointer) {
5645 MOZ_ASSERT(aEvent->AsMouseEvent() != nullptr)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->AsMouseEvent() != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->AsMouseEvent() !=
nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aEvent->AsMouseEvent() != nullptr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5645); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->AsMouseEvent() != nullptr"
")"); do { *((volatile int*)__null) = 5645; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5646 if (!mMouseEnterLeaveHelper) {
5647 mMouseEnterLeaveHelper = new OverOutElementsWrapper(
5648 OverOutElementsWrapper::BoundaryEventType::Mouse);
5649 }
5650 return mMouseEnterLeaveHelper;
5651 }
5652 return mPointersEnterLeaveHelper.GetOrInsertNew(
5653 pointer->pointerId, OverOutElementsWrapper::BoundaryEventType::Pointer);
5654}
5655
5656/* static */
5657void EventStateManager::SetPointerLock(nsIWidget* aWidget,
5658 nsPresContext* aPresContext) {
5659 // Reset mouse wheel transaction
5660 WheelTransaction::EndTransaction();
5661
5662 // Deal with DnD events
5663 nsCOMPtr<nsIDragService> dragService =
5664 do_GetService("@mozilla.org/widget/dragservice;1");
5665
5666 if (PointerLockManager::IsLocked()) {
5667 MOZ_ASSERT(aWidget, "Locking pointer requires a widget")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aWidget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aWidget))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aWidget" " (" "Locking pointer requires a widget"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5667); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWidget" ") ("
"Locking pointer requires a widget" ")"); do { *((volatile int
*)__null) = 5667; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
5668 MOZ_ASSERT(aPresContext, "Locking pointer requires a presContext")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresContext))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPresContext" " ("
"Locking pointer requires a presContext" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5668); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresContext"
") (" "Locking pointer requires a presContext" ")"); do { *(
(volatile int*)__null) = 5668; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
5669
5670 // Release all pointer capture when a pointer lock is successfully applied
5671 // on an element.
5672 PointerEventHandler::ReleaseAllPointerCapture();
5673
5674 // Store the last known ref point so we can reposition the pointer after
5675 // unlock.
5676 sPreLockScreenPoint = LayoutDeviceIntPoint::Round(
5677 sLastScreenPoint * aPresContext->CSSToDevPixelScale());
5678
5679 // Fire a synthetic mouse move to ensure event state is updated. We first
5680 // set the mouse to the center of the window, so that the mouse event
5681 // doesn't report any movement.
5682 // XXX Cannot we do synthesize the native mousemove in the parent process
5683 // with calling LockNativePointer below? Then, we could make this API
5684 // work only in the automation mode.
5685 sLastRefPoint = GetWindowClientRectCenter(aWidget);
5686 aWidget->SynthesizeNativeMouseMove(
5687 sLastRefPoint + aWidget->WidgetToScreenOffset(), nullptr);
5688
5689 // Suppress DnD
5690 if (dragService) {
5691 dragService->Suppress();
5692 }
5693
5694 // Activate native pointer lock on platforms where it is required (Wayland)
5695 aWidget->LockNativePointer();
5696 } else {
5697 if (aWidget) {
5698 // Deactivate native pointer lock on platforms where it is required
5699 aWidget->UnlockNativePointer();
5700 }
5701
5702 // Reset SynthCenteringPoint to invalid so that next time we start
5703 // locking pointer, it has its initial value.
5704 sSynthCenteringPoint = kInvalidRefPoint;
5705 if (aWidget) {
5706 // Unlocking, so return pointer to the original position by firing a
5707 // synthetic mouse event. We first reset sLastRefPoint to its
5708 // pre-pointerlock position, so that the synthetic mouse event reports
5709 // no movement.
5710 sLastRefPoint = sPreLockScreenPoint - aWidget->WidgetToScreenOffset();
5711 // XXX Cannot we do synthesize the native mousemove in the parent process
5712 // with calling `UnlockNativePointer` above? Then, we could make this
5713 // API work only in the automation mode.
5714 aWidget->SynthesizeNativeMouseMove(sPreLockScreenPoint, nullptr);
5715 }
5716
5717 // Unsuppress DnD
5718 if (dragService) {
5719 dragService->Unsuppress();
5720 }
5721 }
5722}
5723
5724void EventStateManager::GenerateDragDropEnterExit(nsPresContext* aPresContext,
5725 WidgetDragEvent* aDragEvent) {
5726 // Hold onto old target content through the event and reset after.
5727 nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
5728
5729 switch (aDragEvent->mMessage) {
5730 case eDragOver: {
5731 // when dragging from one frame to another, events are fired in the
5732 // order: dragexit, dragenter, dragleave
5733 if (sLastDragOverFrame != mCurrentTarget) {
5734 // We'll need the content, too, to check if it changed separately from
5735 // the frames.
5736 nsCOMPtr<nsIContent> lastContent;
5737 nsCOMPtr<nsIContent> targetContent;
5738 mCurrentTarget->GetContentForEvent(aDragEvent,
5739 getter_AddRefs(targetContent));
5740 if (targetContent && targetContent->IsText()) {
5741 targetContent = targetContent->GetFlattenedTreeParent();
5742 }
5743
5744 if (sLastDragOverFrame) {
5745 // The frame has changed but the content may not have. Check before
5746 // dispatching to content
5747 sLastDragOverFrame->GetContentForEvent(aDragEvent,
5748 getter_AddRefs(lastContent));
5749 if (lastContent && lastContent->IsText()) {
5750 lastContent = lastContent->GetFlattenedTreeParent();
5751 }
5752
5753 RefPtr<nsPresContext> presContext = sLastDragOverFrame->PresContext();
5754 FireDragEnterOrExit(presContext, aDragEvent, eDragExit, targetContent,
5755 lastContent, sLastDragOverFrame);
5756 nsIContent* target = sLastDragOverFrame
5757 ? sLastDragOverFrame.GetFrame()->GetContent()
5758 : nullptr;
5759 // XXXedgar, look like we need to consider fission OOP iframe, too.
5760 if (IsTopLevelRemoteTarget(target)) {
5761 // Dragging something and moving from web content to chrome only
5762 // fires dragexit and dragleave to xul:browser. We have to forward
5763 // dragexit to sLastDragOverFrame when its content is a remote
5764 // target. We don't forward dragleave since it's generated from
5765 // dragexit.
5766 WidgetDragEvent remoteEvent(aDragEvent->IsTrusted(), eDragExit,
5767 aDragEvent->mWidget);
5768 remoteEvent.AssignDragEventData(*aDragEvent, true);
5769 remoteEvent.mFlags.mIsSynthesizedForTests =
5770 aDragEvent->mFlags.mIsSynthesizedForTests;
5771 nsEventStatus remoteStatus = nsEventStatus_eIgnore;
5772 HandleCrossProcessEvent(&remoteEvent, &remoteStatus);
5773 }
5774 }
5775
5776 AutoWeakFrame currentTraget = mCurrentTarget;
5777 FireDragEnterOrExit(aPresContext, aDragEvent, eDragEnter, lastContent,
5778 targetContent, currentTraget);
5779
5780 if (sLastDragOverFrame) {
5781 RefPtr<nsPresContext> presContext = sLastDragOverFrame->PresContext();
5782 FireDragEnterOrExit(presContext, aDragEvent, eDragLeave,
5783 targetContent, lastContent, sLastDragOverFrame);
5784 }
5785
5786 sLastDragOverFrame = mCurrentTarget;
5787 }
5788 } break;
5789
5790 case eDragExit: {
5791 // This is actually the window mouse exit event.
5792 if (sLastDragOverFrame) {
5793 nsCOMPtr<nsIContent> lastContent;
5794 sLastDragOverFrame->GetContentForEvent(aDragEvent,
5795 getter_AddRefs(lastContent));
5796
5797 RefPtr<nsPresContext> lastDragOverFramePresContext =
5798 sLastDragOverFrame->PresContext();
5799 FireDragEnterOrExit(lastDragOverFramePresContext, aDragEvent, eDragExit,
5800 nullptr, lastContent, sLastDragOverFrame);
5801 FireDragEnterOrExit(lastDragOverFramePresContext, aDragEvent,
5802 eDragLeave, nullptr, lastContent,
5803 sLastDragOverFrame);
5804
5805 sLastDragOverFrame = nullptr;
5806 }
5807 } break;
5808
5809 default:
5810 break;
5811 }
5812
5813 // reset mCurretTargetContent to what it was
5814 mCurrentTargetContent = targetBeforeEvent;
5815
5816 // Now flush all pending notifications, for better responsiveness.
5817 FlushLayout(aPresContext);
5818}
5819
5820void EventStateManager::FireDragEnterOrExit(nsPresContext* aPresContext,
5821 WidgetDragEvent* aDragEvent,
5822 EventMessage aMessage,
5823 nsIContent* aRelatedTarget,
5824 nsIContent* aTargetContent,
5825 AutoWeakFrame& aTargetFrame) {
5826 MOZ_ASSERT(aMessage == eDragLeave || aMessage == eDragExit ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eDragLeave || aMessage == eDragExit || aMessage
== eDragEnter)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aMessage == eDragLeave || aMessage
== eDragExit || aMessage == eDragEnter))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eDragLeave || aMessage == eDragExit || aMessage == eDragEnter"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5827); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eDragLeave || aMessage == eDragExit || aMessage == eDragEnter"
")"); do { *((volatile int*)__null) = 5827; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5827 aMessage == eDragEnter)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMessage == eDragLeave || aMessage == eDragExit || aMessage
== eDragEnter)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(aMessage == eDragLeave || aMessage
== eDragExit || aMessage == eDragEnter))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aMessage == eDragLeave || aMessage == eDragExit || aMessage == eDragEnter"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5827); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMessage == eDragLeave || aMessage == eDragExit || aMessage == eDragEnter"
")"); do { *((volatile int*)__null) = 5827; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5828 nsEventStatus status = nsEventStatus_eIgnore;
5829 WidgetDragEvent event(aDragEvent->IsTrusted(), aMessage, aDragEvent->mWidget);
5830 event.AssignDragEventData(*aDragEvent, false);
5831 event.mFlags.mIsSynthesizedForTests =
5832 aDragEvent->mFlags.mIsSynthesizedForTests;
5833 event.mRelatedTarget = aRelatedTarget;
5834 if (aMessage == eDragExit && !StaticPrefs::dom_event_dragexit_enabled()) {
5835 event.mFlags.mOnlyChromeDispatch = true;
5836 }
5837
5838 mCurrentTargetContent = aTargetContent;
5839
5840 if (aTargetContent != aRelatedTarget) {
5841 // XXX This event should still go somewhere!!
5842 if (aTargetContent) {
5843 EventDispatcher::Dispatch(aTargetContent, aPresContext, &event, nullptr,
5844 &status);
5845 }
5846
5847 // adjust the drag hover if the dragenter event was cancelled or this is a
5848 // drag exit
5849 if (status == nsEventStatus_eConsumeNoDefault || aMessage == eDragExit) {
5850 SetContentState((aMessage == eDragEnter) ? aTargetContent : nullptr,
5851 ElementState::DRAGOVER);
5852 }
5853
5854 // collect any changes to moz cursor settings stored in the event's
5855 // data transfer.
5856 UpdateDragDataTransfer(&event);
5857 }
5858
5859 // Finally dispatch the event to the frame
5860 if (aTargetFrame) {
5861 aTargetFrame->HandleEvent(aPresContext, &event, &status);
5862 }
5863}
5864
5865void EventStateManager::UpdateDragDataTransfer(WidgetDragEvent* dragEvent) {
5866 NS_ASSERTION(dragEvent, "drag event is null in UpdateDragDataTransfer!")do { if (!(dragEvent)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "drag event is null in UpdateDragDataTransfer!"
, "dragEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5866); MOZ_PretendNoReturn(); } } while (0)
;
5867 if (!dragEvent->mDataTransfer) {
5868 return;
5869 }
5870
5871 nsCOMPtr<nsIDragSession> dragSession =
5872 nsContentUtils::GetDragSession(mPresContext);
5873
5874 if (dragSession) {
5875 // the initial dataTransfer is the one from the dragstart event that
5876 // was set on the dragSession when the drag began.
5877 RefPtr<DataTransfer> initialDataTransfer = dragSession->GetDataTransfer();
5878 if (initialDataTransfer) {
5879 // retrieve the current moz cursor setting and save it.
5880 nsAutoString mozCursor;
5881 dragEvent->mDataTransfer->GetMozCursor(mozCursor);
5882 initialDataTransfer->SetMozCursor(mozCursor);
5883 }
5884 }
5885}
5886
5887nsresult EventStateManager::SetClickCount(WidgetMouseEvent* aEvent,
5888 nsEventStatus* aStatus,
5889 nsIContent* aOverrideClickTarget) {
5890 nsCOMPtr<nsIContent> mouseContent = aOverrideClickTarget;
5891 if (!mouseContent && mCurrentTarget) {
5892 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(mouseContent));
5893 }
5894 if (mouseContent && mouseContent->IsText()) {
5895 nsINode* parent = mouseContent->GetFlattenedTreeParentNode();
5896 if (parent && parent->IsContent()) {
5897 mouseContent = parent->AsContent();
5898 }
5899 }
5900
5901 LastMouseDownInfo& mouseDownInfo = GetLastMouseDownInfo(aEvent->mButton);
5902 if (aEvent->mMessage == eMouseDown) {
5903 mouseDownInfo.mLastMouseDownContent =
5904 !aEvent->mClickEventPrevented ? mouseContent : nullptr;
5905
5906 if (mouseDownInfo.mLastMouseDownContent) {
5907 if (HTMLInputElement* input = HTMLInputElement::FromNodeOrNull(
5908 mouseDownInfo.mLastMouseDownContent)) {
5909 mouseDownInfo.mLastMouseDownInputControlType =
5910 Some(input->ControlType());
5911 } else if (mouseDownInfo.mLastMouseDownContent
5912 ->IsInNativeAnonymousSubtree()) {
5913 if (HTMLInputElement* input = HTMLInputElement::FromNodeOrNull(
5914 mouseDownInfo.mLastMouseDownContent
5915 ->GetFlattenedTreeParent())) {
5916 mouseDownInfo.mLastMouseDownInputControlType =
5917 Some(input->ControlType());
5918 }
5919 }
5920 }
5921 } else {
5922 aEvent->mClickTarget =
5923 !aEvent->mClickEventPrevented
5924 ? GetCommonAncestorForMouseUp(
5925 mouseContent, mouseDownInfo.mLastMouseDownContent,
5926 mouseDownInfo.mLastMouseDownInputControlType)
5927 : nullptr;
5928 if (aEvent->mClickTarget) {
5929 aEvent->mClickCount = mouseDownInfo.mClickCount;
5930 mouseDownInfo.mClickCount = 0;
5931 } else {
5932 aEvent->mClickCount = 0;
5933 }
5934 mouseDownInfo.mLastMouseDownContent = nullptr;
5935 mouseDownInfo.mLastMouseDownInputControlType = Nothing();
5936 }
5937
5938 return NS_OK;
5939}
5940
5941// static
5942bool EventStateManager::EventCausesClickEvents(
5943 const WidgetMouseEvent& aMouseEvent) {
5944 if (NS_WARN_IF(aMouseEvent.mMessage != eMouseUp)NS_warn_if_impl(aMouseEvent.mMessage != eMouseUp, "aMouseEvent.mMessage != eMouseUp"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5944)
) {
5945 return false;
5946 }
5947 // If the mouseup event is synthesized event, we don't need to dispatch
5948 // click events.
5949 if (!aMouseEvent.IsReal()) {
5950 return false;
5951 }
5952 // If mouse is still over same element, clickcount will be > 1.
5953 // If it has moved it will be zero, so no click.
5954 if (!aMouseEvent.mClickCount || !aMouseEvent.mClickTarget) {
5955 return false;
5956 }
5957 // If click event was explicitly prevented, we shouldn't dispatch it.
5958 if (aMouseEvent.mClickEventPrevented) {
5959 return false;
5960 }
5961 // Check that the window isn't disabled before firing a click
5962 // (see bug 366544).
5963 return !(aMouseEvent.mWidget && !aMouseEvent.mWidget->IsEnabled());
5964}
5965
5966nsresult EventStateManager::InitAndDispatchClickEvent(
5967 WidgetMouseEvent* aMouseUpEvent, nsEventStatus* aStatus,
5968 EventMessage aMessage, PresShell* aPresShell, nsIContent* aMouseUpContent,
5969 AutoWeakFrame aCurrentTarget, bool aNoContentDispatch,
5970 nsIContent* aOverrideClickTarget) {
5971 MOZ_ASSERT(aMouseUpEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseUpEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseUpEvent))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aMouseUpEvent",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5971); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpEvent"
")"); do { *((volatile int*)__null) = 5971; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
16
Taking false branch
17
Loop condition is false. Exiting loop
5972 MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(EventCausesClickEvents(*aMouseUpEvent))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(EventCausesClickEvents(*aMouseUpEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("EventCausesClickEvents(*aMouseUpEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5972); AnnotateMozCrashReason("MOZ_ASSERT" "(" "EventCausesClickEvents(*aMouseUpEvent)"
")"); do { *((volatile int*)__null) = 5972; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
18
Taking false branch
5973 MOZ_ASSERT(aMouseUpContent || aCurrentTarget || aOverrideClickTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseUpContent || aCurrentTarget || aOverrideClickTarget
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aMouseUpContent || aCurrentTarget || aOverrideClickTarget
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aMouseUpContent || aCurrentTarget || aOverrideClickTarget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 5973); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpContent || aCurrentTarget || aOverrideClickTarget"
")"); do { *((volatile int*)__null) = 5973; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
19
Loop condition is false. Exiting loop
20
Taking false branch
21
Loop condition is false. Exiting loop
5974
5975 Maybe<WidgetPointerEvent> pointerEvent;
5976 Maybe<WidgetMouseEvent> mouseEvent;
22
Calling defaulted default constructor for 'Maybe<mozilla::WidgetMouseEvent>'
33
Returning from default constructor for 'Maybe<mozilla::WidgetMouseEvent>'
5977 if (IsPointerEventMessage(aMessage)) {
34
Assuming the condition is true
35
Taking true branch
5978 pointerEvent.emplace(aMouseUpEvent->IsTrusted(), aMessage,
5979 aMouseUpEvent->mWidget);
5980 } else {
5981 mouseEvent.emplace(aMouseUpEvent->IsTrusted(), aMessage,
5982 aMouseUpEvent->mWidget, WidgetMouseEvent::eReal);
5983 }
5984
5985 WidgetMouseEvent& mouseOrPointerEvent =
5986 pointerEvent.isSome() ? pointerEvent.ref() : mouseEvent.ref();
36
'?' condition is true
5987
5988 mouseOrPointerEvent.mRefPoint = aMouseUpEvent->mRefPoint;
5989 mouseOrPointerEvent.mClickCount = aMouseUpEvent->mClickCount;
5990 mouseOrPointerEvent.mModifiers = aMouseUpEvent->mModifiers;
5991 mouseOrPointerEvent.mButtons = aMouseUpEvent->mButtons;
5992 mouseOrPointerEvent.mTimeStamp = aMouseUpEvent->mTimeStamp;
5993 mouseOrPointerEvent.mFlags.mOnlyChromeDispatch = aNoContentDispatch;
5994 mouseOrPointerEvent.mFlags.mNoContentDispatch = aNoContentDispatch;
5995 mouseOrPointerEvent.mButton = aMouseUpEvent->mButton;
5996 mouseOrPointerEvent.pointerId = aMouseUpEvent->pointerId;
5997 mouseOrPointerEvent.mInputSource = aMouseUpEvent->mInputSource;
5998 nsIContent* target = aMouseUpContent;
5999 nsIFrame* targetFrame = aCurrentTarget;
6000 if (aOverrideClickTarget) {
37
Assuming 'aOverrideClickTarget' is null
38
Taking false branch
6001 target = aOverrideClickTarget;
6002 targetFrame = aOverrideClickTarget->GetPrimaryFrame();
6003 }
6004
6005 if (!target->IsInComposedDoc()) {
39
Taking true branch
6006 return NS_OK;
40
Calling implicit destructor for 'Maybe<mozilla::WidgetMouseEvent>'
41
Calling '~MaybeStorage'
6007 }
6008
6009 // Use local event status for each click event dispatching since it'll be
6010 // cleared by EventStateManager::PreHandleEvent(). Therefore, dispatching
6011 // an event means that previous event status will be ignored.
6012 nsEventStatus status = nsEventStatus_eIgnore;
6013 nsresult rv = aPresShell->HandleEventWithTarget(
6014 &mouseOrPointerEvent, targetFrame, MOZ_KnownLive(target)(target), &status);
6015
6016 // Copy mMultipleActionsPrevented flag from a click event to the mouseup
6017 // event only when it's set to true. It may be set to true if an editor has
6018 // already handled it. This is important to avoid two or more default
6019 // actions handled here.
6020 aMouseUpEvent->mFlags.mMultipleActionsPrevented |=
6021 mouseOrPointerEvent.mFlags.mMultipleActionsPrevented;
6022 // If current status is nsEventStatus_eConsumeNoDefault, we don't need to
6023 // overwrite it.
6024 if (*aStatus == nsEventStatus_eConsumeNoDefault) {
6025 return rv;
6026 }
6027 // If new status is nsEventStatus_eConsumeNoDefault or
6028 // nsEventStatus_eConsumeDoDefault, use it.
6029 if (status == nsEventStatus_eConsumeNoDefault ||
6030 status == nsEventStatus_eConsumeDoDefault) {
6031 *aStatus = status;
6032 return rv;
6033 }
6034 // Otherwise, keep the original status.
6035 return rv;
6036}
6037
6038nsresult EventStateManager::PostHandleMouseUp(
6039 WidgetMouseEvent* aMouseUpEvent, nsEventStatus* aStatus,
6040 nsIContent* aOverrideClickTarget) {
6041 MOZ_ASSERT(aMouseUpEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseUpEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseUpEvent))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aMouseUpEvent",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6041); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpEvent"
")"); do { *((volatile int*)__null) = 6041; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6042 MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(EventCausesClickEvents(*aMouseUpEvent))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(EventCausesClickEvents(*aMouseUpEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("EventCausesClickEvents(*aMouseUpEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6042); AnnotateMozCrashReason("MOZ_ASSERT" "(" "EventCausesClickEvents(*aMouseUpEvent)"
")"); do { *((volatile int*)__null) = 6042; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6043 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6043); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 6043; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6044
6045 RefPtr<PresShell> presShell = mPresContext->GetPresShell();
6046 if (!presShell) {
6047 return NS_OK;
6048 }
6049
6050 nsCOMPtr<nsIContent> clickTarget =
6051 nsIContent::FromEventTargetOrNull(aMouseUpEvent->mClickTarget);
6052 NS_ENSURE_STATE(clickTarget)do { if ((__builtin_expect(!!(!(clickTarget)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "clickTarget" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6052); return NS_ERROR_UNEXPECTED; } } while (false)
;
6053
6054 // Fire click events if the event target is still available.
6055 // Note that do not include the eMouseUp event's status since we ignore it
6056 // for compatibility with the other browsers.
6057 nsEventStatus status = nsEventStatus_eIgnore;
6058 nsresult rv = DispatchClickEvents(presShell, aMouseUpEvent, &status,
6059 clickTarget, aOverrideClickTarget);
6060 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6060)
) {
6061 return rv;
6062 }
6063
6064 // Do not do anything if preceding click events are consumed.
6065 // Note that Chromium dispatches "paste" event and actually pates clipboard
6066 // text into focused editor even if the preceding click events are consumed.
6067 // However, this is different from our traditional behavior and does not
6068 // conform to DOM events. If we need to keep compatibility with Chromium,
6069 // we should change it later.
6070 if (status == nsEventStatus_eConsumeNoDefault) {
6071 *aStatus = nsEventStatus_eConsumeNoDefault;
6072 return NS_OK;
6073 }
6074
6075 // Handle middle click paste if it's enabled and the mouse button is middle.
6076 if (aMouseUpEvent->mButton != MouseButton::eMiddle ||
6077 !WidgetMouseEvent::IsMiddleClickPasteEnabled()) {
6078 return NS_OK;
6079 }
6080 DebugOnly<nsresult> rvIgnored =
6081 HandleMiddleClickPaste(presShell, aMouseUpEvent, &status, nullptr);
6082 NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to paste for a middle click"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6083); } } while (false)
6083 "Failed to paste for a middle click")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rvIgnored
)), 1))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to paste for a middle click"
, "NS_SUCCEEDED(rvIgnored)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6083); } } while (false)
;
6084
6085 // If new status is nsEventStatus_eConsumeNoDefault or
6086 // nsEventStatus_eConsumeDoDefault, use it.
6087 if (*aStatus != nsEventStatus_eConsumeNoDefault &&
6088 (status == nsEventStatus_eConsumeNoDefault ||
6089 status == nsEventStatus_eConsumeDoDefault)) {
6090 *aStatus = status;
6091 }
6092
6093 // Don't return error even if middle mouse paste fails since we haven't
6094 // handled it here.
6095 return NS_OK;
6096}
6097
6098nsresult EventStateManager::DispatchClickEvents(
6099 PresShell* aPresShell, WidgetMouseEvent* aMouseUpEvent,
6100 nsEventStatus* aStatus, nsIContent* aClickTarget,
6101 nsIContent* aOverrideClickTarget) {
6102 MOZ_ASSERT(aPresShell)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresShell)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresShell))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aPresShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6102); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresShell"
")"); do { *((volatile int*)__null) = 6102; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1
Assuming 'aPresShell' is non-null
2
Taking false branch
3
Loop condition is false. Exiting loop
6103 MOZ_ASSERT(aMouseUpEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseUpEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseUpEvent))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aMouseUpEvent",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6103); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseUpEvent"
")"); do { *((volatile int*)__null) = 6103; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4
Assuming 'aMouseUpEvent' is non-null
5
Taking false branch
6
Loop condition is false. Exiting loop
6104 MOZ_ASSERT(EventCausesClickEvents(*aMouseUpEvent))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(EventCausesClickEvents(*aMouseUpEvent))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(EventCausesClickEvents(*aMouseUpEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("EventCausesClickEvents(*aMouseUpEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6104); AnnotateMozCrashReason("MOZ_ASSERT" "(" "EventCausesClickEvents(*aMouseUpEvent)"
")"); do { *((volatile int*)__null) = 6104; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7
Taking false branch
8
Loop condition is false. Exiting loop
6105 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6105); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 6105; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9
Assuming 'aStatus' is non-null
10
Taking false branch
6106 MOZ_ASSERT(aClickTarget || aOverrideClickTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aClickTarget || aOverrideClickTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aClickTarget || aOverrideClickTarget
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"aClickTarget || aOverrideClickTarget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6106); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aClickTarget || aOverrideClickTarget"
")"); do { *((volatile int*)__null) = 6106; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
11
Loop condition is false. Exiting loop
12
Assuming 'aClickTarget' is non-null
13
Taking false branch
6107
6108 bool notDispatchToContents =
6109 (aMouseUpEvent->mButton == MouseButton::eMiddle ||
14
Assuming field 'mButton' is equal to eMiddle
6110 aMouseUpEvent->mButton == MouseButton::eSecondary);
6111
6112 bool fireAuxClick = notDispatchToContents;
6113
6114 AutoWeakFrame currentTarget = aClickTarget->GetPrimaryFrame();
6115 nsresult rv = InitAndDispatchClickEvent(
15
Calling 'EventStateManager::InitAndDispatchClickEvent'
6116 aMouseUpEvent, aStatus, ePointerClick, aPresShell, aClickTarget,
6117 currentTarget, notDispatchToContents, aOverrideClickTarget);
6118 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6118)
) {
6119 return rv;
6120 }
6121
6122 // Fire auxclick event if necessary.
6123 if (fireAuxClick && *aStatus != nsEventStatus_eConsumeNoDefault &&
6124 aClickTarget && aClickTarget->IsInComposedDoc()) {
6125 rv = InitAndDispatchClickEvent(aMouseUpEvent, aStatus, ePointerAuxClick,
6126 aPresShell, aClickTarget, currentTarget,
6127 false, aOverrideClickTarget);
6128 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to dispatch ePointerAuxClick"
, "NS_SUCCEEDED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6129); } } while (false)
6129 "Failed to dispatch ePointerAuxClick")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to dispatch ePointerAuxClick"
, "NS_SUCCEEDED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6129); } } while (false)
;
6130 }
6131
6132 // Fire double click event if click count is 2.
6133 if (aMouseUpEvent->mClickCount == 2 && !fireAuxClick && aClickTarget &&
6134 aClickTarget->IsInComposedDoc()) {
6135 rv = InitAndDispatchClickEvent(aMouseUpEvent, aStatus, eMouseDoubleClick,
6136 aPresShell, aClickTarget, currentTarget,
6137 notDispatchToContents, aOverrideClickTarget);
6138 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6138)
) {
6139 return rv;
6140 }
6141 }
6142
6143 return rv;
6144}
6145
6146nsresult EventStateManager::HandleMiddleClickPaste(
6147 PresShell* aPresShell, WidgetMouseEvent* aMouseEvent,
6148 nsEventStatus* aStatus, EditorBase* aEditorBase) {
6149 MOZ_ASSERT(aPresShell)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresShell)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresShell))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aPresShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6149); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresShell"
")"); do { *((volatile int*)__null) = 6149; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6150 MOZ_ASSERT(aMouseEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aMouseEvent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aMouseEvent))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aMouseEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6150); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aMouseEvent"
")"); do { *((volatile int*)__null) = 6150; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6151 MOZ_ASSERT((aMouseEvent->mMessage == ePointerAuxClick &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aMouseEvent->mMessage == ePointerAuxClick &&
aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents
(*aMouseEvent))>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!((aMouseEvent->mMessage == ePointerAuxClick
&& aMouseEvent->mButton == MouseButton::eMiddle) ||
EventCausesClickEvents(*aMouseEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6153); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
")"); do { *((volatile int*)__null) = 6153; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6152 aMouseEvent->mButton == MouseButton::eMiddle) ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aMouseEvent->mMessage == ePointerAuxClick &&
aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents
(*aMouseEvent))>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!((aMouseEvent->mMessage == ePointerAuxClick
&& aMouseEvent->mButton == MouseButton::eMiddle) ||
EventCausesClickEvents(*aMouseEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6153); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
")"); do { *((volatile int*)__null) = 6153; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6153 EventCausesClickEvents(*aMouseEvent))do { static_assert( mozilla::detail::AssertionConditionType<
decltype((aMouseEvent->mMessage == ePointerAuxClick &&
aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents
(*aMouseEvent))>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!((aMouseEvent->mMessage == ePointerAuxClick
&& aMouseEvent->mButton == MouseButton::eMiddle) ||
EventCausesClickEvents(*aMouseEvent)))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6153); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(aMouseEvent->mMessage == ePointerAuxClick && aMouseEvent->mButton == MouseButton::eMiddle) || EventCausesClickEvents(*aMouseEvent)"
")"); do { *((volatile int*)__null) = 6153; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6154 MOZ_ASSERT(aStatus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStatus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStatus))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aStatus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6154); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStatus" ")"
); do { *((volatile int*)__null) = 6154; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6155 MOZ_ASSERT(*aStatus != nsEventStatus_eConsumeNoDefault)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aStatus != nsEventStatus_eConsumeNoDefault)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(*aStatus != nsEventStatus_eConsumeNoDefault))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("*aStatus != nsEventStatus_eConsumeNoDefault"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6155); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aStatus != nsEventStatus_eConsumeNoDefault"
")"); do { *((volatile int*)__null) = 6155; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6156
6157 // Even if we're called twice or more for a mouse operation, we should
6158 // handle only once. Although mMultipleActionsPrevented may be set to
6159 // true by different event handler in the future, we can use it for now.
6160 if (aMouseEvent->mFlags.mMultipleActionsPrevented) {
6161 return NS_OK;
6162 }
6163 aMouseEvent->mFlags.mMultipleActionsPrevented = true;
6164
6165 RefPtr<Selection> selection;
6166 if (aEditorBase) {
6167 selection = aEditorBase->GetSelection();
6168 if (NS_WARN_IF(!selection)NS_warn_if_impl(!selection, "!selection", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6168)
) {
6169 return NS_ERROR_FAILURE;
6170 }
6171 } else {
6172 Document* document = aPresShell->GetDocument();
6173 if (NS_WARN_IF(!document)NS_warn_if_impl(!document, "!document", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6173)
) {
6174 return NS_ERROR_FAILURE;
6175 }
6176 selection = nsCopySupport::GetSelectionForCopy(document);
6177 if (NS_WARN_IF(!selection)NS_warn_if_impl(!selection, "!selection", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6177)
) {
6178 return NS_ERROR_FAILURE;
6179 }
6180
6181 const nsRange* range = selection->GetRangeAt(0);
6182 if (range) {
6183 nsINode* target = range->GetStartContainer();
6184 if (target && target->OwnerDoc()->IsInChromeDocShell()) {
6185 // In Chrome document, limit middle-click pasting to only the editor
6186 // because it looks odd if pasting works in the focused editor when you
6187 // middle-click toolbar or something which are far from the editor.
6188 // However, as DevTools especially Web Console module assumes that paste
6189 // event will be fired when middle-click even on not editor, don't limit
6190 // it.
6191 return NS_OK;
6192 }
6193 }
6194 }
6195
6196 // Don't modify selection here because we've already set caret to the point
6197 // at "mousedown" event.
6198
6199 nsIClipboard::ClipboardType clipboardType = nsIClipboard::kGlobalClipboard;
6200 nsCOMPtr<nsIClipboard> clipboardService =
6201 do_GetService("@mozilla.org/widget/clipboard;1");
6202 if (clipboardService && clipboardService->IsClipboardTypeSupported(
6203 nsIClipboard::kSelectionClipboard)) {
6204 clipboardType = nsIClipboard::kSelectionClipboard;
6205 }
6206
6207 RefPtr<DataTransfer> dataTransfer;
6208 if (aEditorBase) {
6209 // Create the same DataTransfer object here so we can share it between
6210 // the clipboard event and the call to HandlePaste below. This prevents
6211 // race conditions with Content Analysis on like we see in bug 1918027.
6212 dataTransfer =
6213 aEditorBase->CreateDataTransferForPaste(ePaste, clipboardType);
6214 }
6215 const auto clearDataTransfer = MakeScopeExit([&] {
6216 if (dataTransfer) {
6217 dataTransfer->ClearForPaste();
6218 }
6219 });
6220
6221 // Fire ePaste event by ourselves since we need to dispatch "paste" event
6222 // even if the middle click event was consumed for compatibility with
6223 // Chromium.
6224 if (!nsCopySupport::FireClipboardEvent(ePaste, Some(clipboardType),
6225 aPresShell, selection, dataTransfer)) {
6226 *aStatus = nsEventStatus_eConsumeNoDefault;
6227 return NS_OK;
6228 }
6229
6230 // Although we've fired "paste" event, there is no editor to accept the
6231 // clipboard content.
6232 if (!aEditorBase) {
6233 return NS_OK;
6234 }
6235
6236 // Check if the editor is still the good target to paste.
6237 if (aEditorBase->Destroyed() || aEditorBase->IsReadonly()) {
6238 // XXX Should we consume the event when the editor is readonly and/or
6239 // disabled?
6240 return NS_OK;
6241 }
6242
6243 // The selection may have been modified during reflow. Therefore, we
6244 // should adjust event target to pass IsAcceptableInputEvent().
6245 const nsRange* range = selection->GetRangeAt(0);
6246 if (!range) {
6247 return NS_OK;
6248 }
6249 WidgetMouseEvent mouseEvent(*aMouseEvent);
6250 mouseEvent.mOriginalTarget = range->GetStartContainer();
6251 if (NS_WARN_IF(!mouseEvent.mOriginalTarget)NS_warn_if_impl(!mouseEvent.mOriginalTarget, "!mouseEvent.mOriginalTarget"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6251)
||
6252 !aEditorBase->IsAcceptableInputEvent(&mouseEvent)) {
6253 return NS_OK;
6254 }
6255
6256 // If Control key is pressed, we should paste clipboard content as
6257 // quotation. Otherwise, paste it as is.
6258 if (aMouseEvent->IsControl()) {
6259 DebugOnly<nsresult> rv = aEditorBase->PasteAsQuotationAsAction(
6260 clipboardType, EditorBase::DispatchPasteEvent::No, dataTransfer);
6261 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to paste as quotation")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to paste as quotation"
, "NS_SUCCEEDED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6261); } } while (false)
;
6262 } else {
6263 DebugOnly<nsresult> rv = aEditorBase->PasteAsAction(
6264 clipboardType, EditorBase::DispatchPasteEvent::No, dataTransfer);
6265 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to paste")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Failed to paste", "NS_SUCCEEDED(rv)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6265); } } while (false)
;
6266 }
6267 *aStatus = nsEventStatus_eConsumeNoDefault;
6268
6269 return NS_OK;
6270}
6271
6272void EventStateManager::ConsumeInteractionData(
6273 Record<nsString, dom::InteractionData>& aInteractions) {
6274 OnTypingInteractionEnded();
6275
6276 aInteractions.Entries().Clear();
6277 auto newEntry = aInteractions.Entries().AppendElement();
6278 newEntry->mKey = u"Typing"_ns;
6279 newEntry->mValue = gTypingInteraction;
6280 gTypingInteraction = {};
6281}
6282
6283nsIFrame* EventStateManager::GetEventTarget() {
6284 PresShell* presShell;
6285 if (mCurrentTarget || !mPresContext ||
6286 !(presShell = mPresContext->GetPresShell())) {
6287 return mCurrentTarget;
6288 }
6289
6290 if (mCurrentTargetContent) {
6291 mCurrentTarget = mPresContext->GetPrimaryFrameFor(mCurrentTargetContent);
6292 if (mCurrentTarget) {
6293 return mCurrentTarget;
6294 }
6295 }
6296
6297 nsIFrame* frame = presShell->GetCurrentEventFrame();
6298 return (mCurrentTarget = frame);
6299}
6300
6301already_AddRefed<nsIContent> EventStateManager::GetEventTargetContent(
6302 WidgetEvent* aEvent) {
6303 if (aEvent && (aEvent->mMessage == eFocus || aEvent->mMessage == eBlur)) {
6304 nsCOMPtr<nsIContent> content = GetFocusedElement();
6305 return content.forget();
6306 }
6307
6308 if (mCurrentTargetContent) {
6309 nsCOMPtr<nsIContent> content = mCurrentTargetContent;
6310 return content.forget();
6311 }
6312
6313 nsCOMPtr<nsIContent> content;
6314 if (PresShell* presShell = mPresContext->GetPresShell()) {
6315 content = presShell->GetEventTargetContent(aEvent);
6316 }
6317
6318 // Some events here may set mCurrentTarget but not set the corresponding
6319 // event target in the PresShell.
6320 if (!content && mCurrentTarget) {
6321 mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(content));
6322 }
6323
6324 return content.forget();
6325}
6326
6327static Element* GetLabelTarget(nsIContent* aPossibleLabel) {
6328 mozilla::dom::HTMLLabelElement* label =
6329 mozilla::dom::HTMLLabelElement::FromNode(aPossibleLabel);
6330 if (!label) return nullptr;
6331
6332 return label->GetLabeledElement();
6333}
6334
6335/* static */
6336inline void EventStateManager::DoStateChange(Element* aElement,
6337 ElementState aState,
6338 bool aAddState) {
6339 if (aAddState) {
6340 aElement->AddStates(aState);
6341 } else {
6342 aElement->RemoveStates(aState);
6343 }
6344}
6345
6346/* static */
6347inline void EventStateManager::DoStateChange(nsIContent* aContent,
6348 ElementState aState,
6349 bool aStateAdded) {
6350 if (aContent->IsElement()) {
6351 DoStateChange(aContent->AsElement(), aState, aStateAdded);
6352 }
6353}
6354
6355/* static */
6356void EventStateManager::UpdateAncestorState(nsIContent* aStartNode,
6357 nsIContent* aStopBefore,
6358 ElementState aState,
6359 bool aAddState) {
6360 for (; aStartNode && aStartNode != aStopBefore;
6361 aStartNode = aStartNode->GetFlattenedTreeParent()) {
6362 // We might be starting with a non-element (e.g. a text node) and
6363 // if someone is doing something weird might be ending with a
6364 // non-element too (e.g. a document fragment)
6365 if (!aStartNode->IsElement()) {
6366 continue;
6367 }
6368 Element* element = aStartNode->AsElement();
6369 DoStateChange(element, aState, aAddState);
6370 Element* labelTarget = GetLabelTarget(element);
6371 if (labelTarget) {
6372 DoStateChange(labelTarget, aState, aAddState);
6373 }
6374 }
6375
6376 if (aAddState) {
6377 // We might be in a situation where a node was in hover both
6378 // because it was hovered and because the label for it was
6379 // hovered, and while we stopped hovering the node the label is
6380 // still hovered. Or we might have had two nested labels for the
6381 // same node, and while one is no longer hovered the other still
6382 // is. In that situation, the label that's still hovered will be
6383 // aStopBefore or some ancestor of it, and the call we just made
6384 // to UpdateAncestorState with aAddState = false would have
6385 // removed the hover state from the node. But the node should
6386 // still be in hover state. To handle this situation we need to
6387 // keep walking up the tree and any time we find a label mark its
6388 // corresponding node as still in our state.
6389 for (; aStartNode; aStartNode = aStartNode->GetFlattenedTreeParent()) {
6390 if (!aStartNode->IsElement()) {
6391 continue;
6392 }
6393
6394 Element* labelTarget = GetLabelTarget(aStartNode->AsElement());
6395 if (labelTarget && !labelTarget->State().HasState(aState)) {
6396 DoStateChange(labelTarget, aState, true);
6397 }
6398 }
6399 }
6400}
6401
6402// static
6403bool CanContentHaveActiveState(nsIContent& aContent) {
6404 // Editable content can never become active since their default actions
6405 // are disabled. Watch out for editable content in native anonymous
6406 // subtrees though, as they belong to text controls.
6407 return !aContent.IsEditable() || aContent.IsInNativeAnonymousSubtree();
6408}
6409
6410bool EventStateManager::SetContentState(nsIContent* aContent,
6411 ElementState aState) {
6412 MOZ_ASSERT(ManagesState(aState), "Unexpected state")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ManagesState(aState))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ManagesState(aState)))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("ManagesState(aState)"
" (" "Unexpected state" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6412); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ManagesState(aState)"
") (" "Unexpected state" ")"); do { *((volatile int*)__null)
= 6412; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
6413
6414 nsCOMPtr<nsIContent> notifyContent1;
6415 nsCOMPtr<nsIContent> notifyContent2;
6416 bool updateAncestors;
6417
6418 if (aState == ElementState::HOVER || aState == ElementState::ACTIVE) {
6419 // Hover and active are hierarchical
6420 updateAncestors = true;
6421
6422 // check to see that this state is allowed by style. Check dragover too?
6423 // XXX Is this even what we want?
6424 if (mCurrentTarget &&
6425 mCurrentTarget->StyleUI()->UserInput() == StyleUserInput::None) {
6426 return false;
6427 }
6428
6429 if (aState == ElementState::ACTIVE) {
6430 if (aContent && !CanContentHaveActiveState(*aContent)) {
6431 aContent = nullptr;
6432 }
6433 if (aContent != mActiveContent) {
6434 notifyContent1 = aContent;
6435 notifyContent2 = mActiveContent;
6436 mActiveContent = aContent;
6437 }
6438 } else {
6439 NS_ASSERTION(aState == ElementState::HOVER, "How did that happen?")do { if (!(aState == ElementState::HOVER)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "How did that happen?", "aState == ElementState::HOVER", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6439); MOZ_PretendNoReturn(); } } while (0)
;
6440 nsIContent* newHover;
6441
6442 if (mPresContext->IsDynamic()) {
6443 newHover = aContent;
6444 } else {
6445 NS_ASSERTION(!aContent || aContent->GetComposedDoc() ==do { if (!(!aContent || aContent->GetComposedDoc() == mPresContext
->PresShell()->GetDocument())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected document", "!aContent || aContent->GetComposedDoc() == mPresContext->PresShell()->GetDocument()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6447); MOZ_PretendNoReturn(); } } while (0)
6446 mPresContext->PresShell()->GetDocument(),do { if (!(!aContent || aContent->GetComposedDoc() == mPresContext
->PresShell()->GetDocument())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected document", "!aContent || aContent->GetComposedDoc() == mPresContext->PresShell()->GetDocument()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6447); MOZ_PretendNoReturn(); } } while (0)
6447 "Unexpected document")do { if (!(!aContent || aContent->GetComposedDoc() == mPresContext
->PresShell()->GetDocument())) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected document", "!aContent || aContent->GetComposedDoc() == mPresContext->PresShell()->GetDocument()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6447); MOZ_PretendNoReturn(); } } while (0)
;
6448 nsIFrame* frame = aContent ? aContent->GetPrimaryFrame() : nullptr;
6449 if (frame && nsLayoutUtils::IsViewportScrollbarFrame(frame)) {
6450 // The scrollbars of viewport should not ignore the hover state.
6451 // Because they are *not* the content of the web page.
6452 newHover = aContent;
6453 } else {
6454 // All contents of the web page should ignore the hover state.
6455 newHover = nullptr;
6456 }
6457 }
6458
6459 if (newHover != mHoverContent) {
6460 notifyContent1 = newHover;
6461 notifyContent2 = mHoverContent;
6462 mHoverContent = newHover;
6463 }
6464 }
6465 } else {
6466 updateAncestors = false;
6467 if (aState == ElementState::DRAGOVER) {
6468 if (aContent != sDragOverContent) {
6469 notifyContent1 = aContent;
6470 notifyContent2 = sDragOverContent;
6471 sDragOverContent = aContent;
6472 }
6473 } else if (aState == ElementState::URLTARGET) {
6474 if (aContent != mURLTargetContent) {
6475 notifyContent1 = aContent;
6476 notifyContent2 = mURLTargetContent;
6477 mURLTargetContent = aContent;
6478 }
6479 }
6480 }
6481
6482 // We need to keep track of which of notifyContent1 and notifyContent2 is
6483 // getting the state set and which is getting it unset. If both are
6484 // non-null, then notifyContent1 is having the state set and notifyContent2
6485 // is having it unset. But if one of them is null, we need to keep track of
6486 // the right thing for notifyContent1 explicitly.
6487 bool content1StateSet = true;
6488 if (!notifyContent1) {
6489 // This is ok because FindCommonAncestor wouldn't find anything
6490 // anyway if notifyContent1 is null.
6491 notifyContent1 = notifyContent2;
6492 notifyContent2 = nullptr;
6493 content1StateSet = false;
6494 }
6495
6496 if (notifyContent1 && mPresContext) {
6497 EnsureDocument(mPresContext);
6498 if (mDocument) {
6499 nsAutoScriptBlocker scriptBlocker;
6500
6501 if (updateAncestors) {
6502 nsCOMPtr<nsIContent> commonAncestor =
6503 FindCommonAncestor(notifyContent1, notifyContent2);
6504 if (notifyContent2) {
6505 // It's very important to first notify the state removal and
6506 // then the state addition, because due to labels it's
6507 // possible that we're removing state from some element but
6508 // then adding it again (say because mHoverContent changed
6509 // from a control to its label).
6510 UpdateAncestorState(notifyContent2, commonAncestor, aState, false);
6511 }
6512 UpdateAncestorState(notifyContent1, commonAncestor, aState,
6513 content1StateSet);
6514 } else {
6515 if (notifyContent2) {
6516 DoStateChange(notifyContent2, aState, false);
6517 }
6518 DoStateChange(notifyContent1, aState, content1StateSet);
6519 }
6520 }
6521 }
6522
6523 return true;
6524}
6525
6526void EventStateManager::RemoveNodeFromChainIfNeeded(ElementState aState,
6527 nsIContent* aContentRemoved,
6528 bool aNotify) {
6529 MOZ_ASSERT(aState == ElementState::HOVER || aState == ElementState::ACTIVE)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aState == ElementState::HOVER || aState == ElementState
::ACTIVE)>::isValid, "invalid assertion condition"); if ((
__builtin_expect(!!(!(!!(aState == ElementState::HOVER || aState
== ElementState::ACTIVE))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aState == ElementState::HOVER || aState == ElementState::ACTIVE"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6529); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aState == ElementState::HOVER || aState == ElementState::ACTIVE"
")"); do { *((volatile int*)__null) = 6529; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6530 if (!aContentRemoved->IsElement() ||
6531 !aContentRemoved->AsElement()->State().HasState(aState)) {
6532 return;
6533 }
6534
6535 nsCOMPtr<nsIContent>& leaf =
6536 aState == ElementState::HOVER ? mHoverContent : mActiveContent;
6537
6538 MOZ_ASSERT(leaf)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(leaf)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(leaf))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("leaf", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6538); AnnotateMozCrashReason("MOZ_ASSERT" "(" "leaf" ")");
do { *((volatile int*)__null) = 6538; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6539 // These two NS_ASSERTIONS below can fail for Shadow DOM sometimes, and it's
6540 // not clear how to best handle it, see
6541 // https://github.com/whatwg/html/issues/4795 and bug 1551621.
6542 NS_ASSERTION(do { if (!(nsContentUtils::ContentIsFlattenedTreeDescendantOf
(leaf, aContentRemoved))) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"Flat tree and active / hover chain got out of sync", "nsContentUtils::ContentIsFlattenedTreeDescendantOf(leaf, aContentRemoved)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6544); MOZ_PretendNoReturn(); } } while (0)
6543 nsContentUtils::ContentIsFlattenedTreeDescendantOf(leaf, aContentRemoved),do { if (!(nsContentUtils::ContentIsFlattenedTreeDescendantOf
(leaf, aContentRemoved))) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"Flat tree and active / hover chain got out of sync", "nsContentUtils::ContentIsFlattenedTreeDescendantOf(leaf, aContentRemoved)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6544); MOZ_PretendNoReturn(); } } while (0)
6544 "Flat tree and active / hover chain got out of sync")do { if (!(nsContentUtils::ContentIsFlattenedTreeDescendantOf
(leaf, aContentRemoved))) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"Flat tree and active / hover chain got out of sync", "nsContentUtils::ContentIsFlattenedTreeDescendantOf(leaf, aContentRemoved)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6544); MOZ_PretendNoReturn(); } } while (0)
;
6545
6546 nsIContent* newLeaf = aContentRemoved->GetFlattenedTreeParent();
6547 MOZ_ASSERT(!newLeaf || newLeaf->IsElement())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!newLeaf || newLeaf->IsElement())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!newLeaf || newLeaf->IsElement
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!newLeaf || newLeaf->IsElement()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6547); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!newLeaf || newLeaf->IsElement()"
")"); do { *((volatile int*)__null) = 6547; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6548 NS_ASSERTION(!newLeaf || newLeaf->AsElement()->State().HasState(aState),do { if (!(!newLeaf || newLeaf->AsElement()->State().HasState
(aState))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "State got out of sync because of shadow DOM"
, "!newLeaf || newLeaf->AsElement()->State().HasState(aState)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6549); MOZ_PretendNoReturn(); } } while (0)
6549 "State got out of sync because of shadow DOM")do { if (!(!newLeaf || newLeaf->AsElement()->State().HasState
(aState))) { NS_DebugBreak(NS_DEBUG_ASSERTION, "State got out of sync because of shadow DOM"
, "!newLeaf || newLeaf->AsElement()->State().HasState(aState)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6549); MOZ_PretendNoReturn(); } } while (0)
;
6550 if (aNotify) {
6551 SetContentState(newLeaf, aState);
6552 } else {
6553 // We don't update the removed content's state here, since removing NAC
6554 // happens from layout and we don't really want to notify at that point or
6555 // what not.
6556 //
6557 // Also, NAC is not observable and NAC being removed will go away soon.
6558 leaf = newLeaf;
6559 }
6560 MOZ_ASSERT(leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(leaf == newLeaf || (aState == ElementState::ACTIVE &&
!leaf && !CanContentHaveActiveState(*newLeaf)))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(leaf == newLeaf || (aState == ElementState::ACTIVE &&
!leaf && !CanContentHaveActiveState(*newLeaf))))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf && !CanContentHaveActiveState(*newLeaf))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6561); AnnotateMozCrashReason("MOZ_ASSERT" "(" "leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf && !CanContentHaveActiveState(*newLeaf))"
")"); do { *((volatile int*)__null) = 6561; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
6561 !CanContentHaveActiveState(*newLeaf)))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(leaf == newLeaf || (aState == ElementState::ACTIVE &&
!leaf && !CanContentHaveActiveState(*newLeaf)))>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(leaf == newLeaf || (aState == ElementState::ACTIVE &&
!leaf && !CanContentHaveActiveState(*newLeaf))))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf && !CanContentHaveActiveState(*newLeaf))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6561); AnnotateMozCrashReason("MOZ_ASSERT" "(" "leaf == newLeaf || (aState == ElementState::ACTIVE && !leaf && !CanContentHaveActiveState(*newLeaf))"
")"); do { *((volatile int*)__null) = 6561; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6562}
6563
6564void EventStateManager::NativeAnonymousContentRemoved(nsIContent* aContent) {
6565 MOZ_ASSERT(aContent->IsRootOfNativeAnonymousSubtree())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContent->IsRootOfNativeAnonymousSubtree())>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aContent->IsRootOfNativeAnonymousSubtree()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("aContent->IsRootOfNativeAnonymousSubtree()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6565); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsRootOfNativeAnonymousSubtree()"
")"); do { *((volatile int*)__null) = 6565; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6566 RemoveNodeFromChainIfNeeded(ElementState::HOVER, aContent, false);
6567 RemoveNodeFromChainIfNeeded(ElementState::ACTIVE, aContent, false);
6568
6569 nsCOMPtr<nsIContent>& lastLeftMouseDownContent =
6570 mLastLeftMouseDownInfo.mLastMouseDownContent;
6571 if (lastLeftMouseDownContent &&
6572 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
6573 lastLeftMouseDownContent, aContent)) {
6574 lastLeftMouseDownContent = aContent->GetFlattenedTreeParent();
6575 }
6576
6577 nsCOMPtr<nsIContent>& lastMiddleMouseDownContent =
6578 mLastMiddleMouseDownInfo.mLastMouseDownContent;
6579 if (lastMiddleMouseDownContent &&
6580 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
6581 lastMiddleMouseDownContent, aContent)) {
6582 lastMiddleMouseDownContent = aContent->GetFlattenedTreeParent();
6583 }
6584
6585 nsCOMPtr<nsIContent>& lastRightMouseDownContent =
6586 mLastRightMouseDownInfo.mLastMouseDownContent;
6587 if (lastRightMouseDownContent &&
6588 nsContentUtils::ContentIsFlattenedTreeDescendantOf(
6589 lastRightMouseDownContent, aContent)) {
6590 lastRightMouseDownContent = aContent->GetFlattenedTreeParent();
6591 }
6592}
6593
6594void EventStateManager::ContentRemoved(Document* aDocument,
6595 nsIContent* aContent) {
6596 /*
6597 * Anchor and area elements when focused or hovered might make the UI to show
6598 * the current link. We want to make sure that the UI gets informed when they
6599 * are actually removed from the DOM.
6600 */
6601 if (aContent->IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area) &&
6602 (aContent->AsElement()->State().HasAtLeastOneOfStates(
6603 ElementState::FOCUS | ElementState::HOVER))) {
6604 Element* element = aContent->AsElement();
6605 element->LeaveLink(element->GetPresContext(Element::eForComposedDoc));
6606 }
6607
6608 if (aContent->IsElement()) {
6609 if (RefPtr<nsPresContext> presContext = mPresContext) {
6610 IMEStateManager::OnRemoveContent(*presContext,
6611 MOZ_KnownLive(*aContent->AsElement())(*aContent->AsElement()));
6612 }
6613 WheelTransaction::OnRemoveElement(aContent);
6614 }
6615
6616 // inform the focus manager that the content is being removed. If this
6617 // content is focused, the focus will be removed without firing events.
6618 if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
6619 fm->ContentRemoved(aDocument, aContent);
6620 }
6621
6622 RemoveNodeFromChainIfNeeded(ElementState::HOVER, aContent, true);
6623 RemoveNodeFromChainIfNeeded(ElementState::ACTIVE, aContent, true);
6624
6625 if (sDragOverContent &&
6626 sDragOverContent->OwnerDoc() == aContent->OwnerDoc() &&
6627 nsContentUtils::ContentIsFlattenedTreeDescendantOf(sDragOverContent,
6628 aContent)) {
6629 sDragOverContent = nullptr;
6630 }
6631
6632 PointerEventHandler::ReleaseIfCaptureByDescendant(aContent);
6633
6634 if (mMouseEnterLeaveHelper) {
6635 const bool hadMouseOutTarget =
6636 mMouseEnterLeaveHelper->GetOutEventTarget() != nullptr;
6637 mMouseEnterLeaveHelper->ContentRemoved(*aContent);
6638 // If we lose the mouseout target, we need to dispatch mouseover on an
6639 // ancestor. For ensuring the chance to do it before next user input, we
6640 // need a synthetic mouse move.
6641 if (hadMouseOutTarget && !mMouseEnterLeaveHelper->GetOutEventTarget()) {
6642 if (PresShell* presShell =
6643 mPresContext ? mPresContext->GetPresShell() : nullptr) {
6644 presShell->SynthesizeMouseMove(false);
6645 }
6646 }
6647 }
6648 for (const auto& entry : mPointersEnterLeaveHelper) {
6649 if (entry.GetData()) {
6650 entry.GetData()->ContentRemoved(*aContent);
6651 }
6652 }
6653}
6654
6655void EventStateManager::TextControlRootWillBeRemoved(
6656 TextControlElement& aTextControlElement) {
6657 if (!mGestureDownInTextControl || !mGestureDownFrameOwner ||
6658 !mGestureDownFrameOwner->IsInNativeAnonymousSubtree()) {
6659 return;
6660 }
6661 // If we track gesture to start drag in aTextControlElement, we should keep
6662 // tracking it with aTextContrlElement itself for now because this may be
6663 // caused by reframing aTextControlElement which may not be intended by the
6664 // user.
6665 if (&aTextControlElement ==
6666 mGestureDownFrameOwner
6667 ->GetClosestNativeAnonymousSubtreeRootParentOrHost()) {
6668 mGestureDownFrameOwner = &aTextControlElement;
6669 }
6670}
6671
6672void EventStateManager::TextControlRootAdded(
6673 Element& aAnonymousDivElement, TextControlElement& aTextControlElement) {
6674 if (!mGestureDownInTextControl ||
6675 mGestureDownFrameOwner != &aTextControlElement) {
6676 return;
6677 }
6678 // If we track gesture to start drag in aTextControlElement, but the frame
6679 // owner is the text control element itself, the anonymous nodes in it are
6680 // recreated by a reframe. If so, we should keep tracking it with the
6681 // recreated native anonymous node.
6682 mGestureDownFrameOwner =
6683 aAnonymousDivElement.GetFirstChild()
6684 ? aAnonymousDivElement.GetFirstChild()
6685 : static_cast<nsIContent*>(&aAnonymousDivElement);
6686}
6687
6688bool EventStateManager::EventStatusOK(WidgetGUIEvent* aEvent) {
6689 return !(aEvent->mMessage == eMouseDown &&
6690 aEvent->AsMouseEvent()->mButton == MouseButton::ePrimary &&
6691 !sNormalLMouseEventInProcess);
6692}
6693
6694//-------------------------------------------
6695// Access Key Registration
6696//-------------------------------------------
6697void EventStateManager::RegisterAccessKey(Element* aElement, uint32_t aKey) {
6698 if (aElement && !mAccessKeys.Contains(aElement)) {
6699 mAccessKeys.AppendObject(aElement);
6700 }
6701}
6702
6703void EventStateManager::UnregisterAccessKey(Element* aElement, uint32_t aKey) {
6704 if (aElement) {
6705 mAccessKeys.RemoveObject(aElement);
6706 }
6707}
6708
6709uint32_t EventStateManager::GetRegisteredAccessKey(Element* aElement) {
6710 MOZ_ASSERT(aElement)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aElement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aElement))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aElement", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6710); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aElement" ")"
); do { *((volatile int*)__null) = 6710; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6711
6712 if (!mAccessKeys.Contains(aElement)) {
6713 return 0;
6714 }
6715
6716 nsAutoString accessKey;
6717 aElement->GetAttr(nsGkAtoms::accesskey, accessKey);
6718 return accessKey.First();
6719}
6720
6721void EventStateManager::EnsureDocument(nsPresContext* aPresContext) {
6722 if (!mDocument) mDocument = aPresContext->Document();
6723}
6724
6725void EventStateManager::FlushLayout(nsPresContext* aPresContext) {
6726 MOZ_ASSERT(aPresContext, "nullptr ptr")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aPresContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aPresContext))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aPresContext" " ("
"nullptr ptr" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6726); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aPresContext"
") (" "nullptr ptr" ")"); do { *((volatile int*)__null) = 6726
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
6727 if (RefPtr<PresShell> presShell = aPresContext->GetPresShell()) {
6728 presShell->FlushPendingNotifications(FlushType::InterruptibleLayout);
6729 }
6730}
6731
6732Element* EventStateManager::GetFocusedElement() {
6733 nsFocusManager* fm = nsFocusManager::GetFocusManager();
6734 EnsureDocument(mPresContext);
6735 if (!fm || !mDocument) {
6736 return nullptr;
6737 }
6738
6739 nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
6740 return nsFocusManager::GetFocusedDescendant(
6741 mDocument->GetWindow(), nsFocusManager::eOnlyCurrentWindow,
6742 getter_AddRefs(focusedWindow));
6743}
6744
6745//-------------------------------------------------------
6746// Return true if the docshell is visible
6747
6748bool EventStateManager::IsShellVisible(nsIDocShell* aShell) {
6749 NS_ASSERTION(aShell, "docshell is null")do { if (!(aShell)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "docshell is null"
, "aShell", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6749); MOZ_PretendNoReturn(); } } while (0)
;
6750
6751 nsCOMPtr<nsIBaseWindow> basewin = do_QueryInterface(aShell);
6752 if (!basewin) return true;
6753
6754 bool isVisible = true;
6755 basewin->GetVisibility(&isVisible);
6756
6757 // We should be doing some additional checks here so that
6758 // we don't tab into hidden tabs of tabbrowser. -bryner
6759
6760 return isVisible;
6761}
6762
6763nsresult EventStateManager::DoContentCommandEvent(
6764 WidgetContentCommandEvent* aEvent) {
6765 EnsureDocument(mPresContext);
6766 NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(mDocument)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mDocument" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6766); return NS_ERROR_FAILURE; } } while (false)
;
6767 nsCOMPtr<nsPIDOMWindowOuter> window(mDocument->GetWindow());
6768 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(window)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "window" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6768); return NS_ERROR_FAILURE; } } while (false)
;
6769
6770 nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
6771 NS_ENSURE_TRUE(root, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(root)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "root" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6771); return NS_ERROR_FAILURE; } } while (false)
;
6772 const char* cmd;
6773 bool maybeNeedToHandleInRemote = false;
6774 switch (aEvent->mMessage) {
6775 case eContentCommandCut:
6776 cmd = "cmd_cut";
6777 maybeNeedToHandleInRemote = true;
6778 break;
6779 case eContentCommandCopy:
6780 cmd = "cmd_copy";
6781 maybeNeedToHandleInRemote = true;
6782 break;
6783 case eContentCommandPaste:
6784 cmd = "cmd_paste";
6785 maybeNeedToHandleInRemote = true;
6786 break;
6787 case eContentCommandDelete:
6788 cmd = "cmd_delete";
6789 maybeNeedToHandleInRemote = true;
6790 break;
6791 case eContentCommandUndo:
6792 cmd = "cmd_undo";
6793 maybeNeedToHandleInRemote = true;
6794 break;
6795 case eContentCommandRedo:
6796 cmd = "cmd_redo";
6797 maybeNeedToHandleInRemote = true;
6798 break;
6799 case eContentCommandPasteTransferable:
6800 cmd = "cmd_pasteTransferable";
6801 break;
6802 case eContentCommandLookUpDictionary:
6803 cmd = "cmd_lookUpDictionary";
6804 break;
6805 default:
6806 return NS_ERROR_NOT_IMPLEMENTED;
6807 }
6808 if (XRE_IsParentProcess() && maybeNeedToHandleInRemote) {
6809 if (BrowserParent* remote = BrowserParent::GetFocused()) {
6810 if (!aEvent->mOnlyEnabledCheck) {
6811 remote->SendSimpleContentCommandEvent(*aEvent);
6812 }
6813 // XXX The command may be disabled in the parent process. Perhaps, we
6814 // should set actual enabled state in the parent process here and there
6815 // should be another bool flag which indicates whether the content is sent
6816 // to a remote process.
6817 aEvent->mIsEnabled = true;
6818 aEvent->mSucceeded = true;
6819 return NS_OK;
6820 }
6821 }
6822 // If user tries to do something, user must try to do it in visible window.
6823 // So, let's retrieve controller of visible window.
6824 nsCOMPtr<nsIController> controller;
6825 nsresult rv =
6826 root->GetControllerForCommand(cmd, true, getter_AddRefs(controller));
6827 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6827); return rv; } } while (false)
;
6828 if (!controller) {
6829 // When GetControllerForCommand succeeded but there is no controller, the
6830 // command isn't supported.
6831 aEvent->mIsEnabled = false;
6832 } else {
6833 bool canDoIt;
6834 rv = controller->IsCommandEnabled(cmd, &canDoIt);
6835 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6835); return rv; } } while (false)
;
6836 aEvent->mIsEnabled = canDoIt;
6837 if (canDoIt && !aEvent->mOnlyEnabledCheck) {
6838 switch (aEvent->mMessage) {
6839 case eContentCommandPasteTransferable: {
6840 BrowserParent* remote = BrowserParent::GetFocused();
6841 if (remote) {
6842 IPCTransferable ipcTransferable;
6843 nsContentUtils::TransferableToIPCTransferable(
6844 aEvent->mTransferable, &ipcTransferable, false,
6845 remote->Manager());
6846 remote->SendPasteTransferable(std::move(ipcTransferable));
6847 rv = NS_OK;
6848 } else {
6849 nsCOMPtr<nsICommandController> commandController =
6850 do_QueryInterface(controller);
6851 NS_ENSURE_STATE(commandController)do { if ((__builtin_expect(!!(!(commandController)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "commandController" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6851); return NS_ERROR_UNEXPECTED; } } while (false)
;
6852
6853 RefPtr<nsCommandParams> params = new nsCommandParams();
6854 rv = params->SetISupports("transferable", aEvent->mTransferable);
6855 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6855)
) {
6856 return rv;
6857 }
6858 rv = commandController->DoCommandWithParams(cmd, params);
6859 }
6860 break;
6861 }
6862
6863 case eContentCommandLookUpDictionary: {
6864 nsCOMPtr<nsICommandController> commandController =
6865 do_QueryInterface(controller);
6866 if (NS_WARN_IF(!commandController)NS_warn_if_impl(!commandController, "!commandController", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6866)
) {
6867 return NS_ERROR_FAILURE;
6868 }
6869
6870 RefPtr<nsCommandParams> params = new nsCommandParams();
6871 rv = params->SetInt("x", aEvent->mRefPoint.x);
6872 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6872)
) {
6873 return rv;
6874 }
6875
6876 rv = params->SetInt("y", aEvent->mRefPoint.y);
6877 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6877)
) {
6878 return rv;
6879 }
6880
6881 rv = commandController->DoCommandWithParams(cmd, params);
6882 break;
6883 }
6884
6885 default:
6886 rv = controller->DoCommand(cmd);
6887 break;
6888 }
6889 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6889); return rv; } } while (false)
;
6890 }
6891 }
6892 aEvent->mSucceeded = true;
6893 return NS_OK;
6894}
6895
6896nsresult EventStateManager::DoContentCommandInsertTextEvent(
6897 WidgetContentCommandEvent* aEvent) {
6898 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6898); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 6898; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6899 MOZ_ASSERT(aEvent->mMessage == eContentCommandInsertText)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eContentCommandInsertText)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aEvent->mMessage == eContentCommandInsertText))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eContentCommandInsertText"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6899); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eContentCommandInsertText"
")"); do { *((volatile int*)__null) = 6899; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6900 MOZ_DIAGNOSTIC_ASSERT(aEvent->mString.isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mString.isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mString.isSome())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->mString.isSome()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6900); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aEvent->mString.isSome()"
")"); do { *((volatile int*)__null) = 6900; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6901 MOZ_DIAGNOSTIC_ASSERT(!aEvent->mString.ref().IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEvent->mString.ref().IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aEvent->mString.ref().IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aEvent->mString.ref().IsEmpty()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6901); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!aEvent->mString.ref().IsEmpty()"
")"); do { *((volatile int*)__null) = 6901; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6902
6903 aEvent->mIsEnabled = false;
6904 aEvent->mSucceeded = false;
6905
6906 NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(mPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6906); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
6907
6908 if (XRE_IsParentProcess()) {
6909 // Handle it in focused content process if there is.
6910 if (BrowserParent* remote = BrowserParent::GetFocused()) {
6911 if (!aEvent->mOnlyEnabledCheck) {
6912 remote->SendInsertText(*aEvent);
6913 }
6914 // XXX The remote process may be not editable right now. Therefore, this
6915 // may be different from actual state in the remote process.
6916 aEvent->mIsEnabled = true;
6917 aEvent->mSucceeded = true;
6918 return NS_OK;
6919 }
6920 }
6921
6922 // If there is no active editor in this process, we should treat the command
6923 // is disabled.
6924 RefPtr<EditorBase> activeEditor =
6925 nsContentUtils::GetActiveEditor(mPresContext);
6926 if (!activeEditor) {
6927 aEvent->mSucceeded = true;
6928 return NS_OK;
6929 }
6930
6931 nsresult rv = activeEditor->InsertTextAsAction(aEvent->mString.ref());
6932 aEvent->mIsEnabled = rv != NS_SUCCESS_DOM_NO_OPERATION;
6933 aEvent->mSucceeded = NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)));
6934 return NS_OK;
6935}
6936
6937nsresult EventStateManager::DoContentCommandReplaceTextEvent(
6938 WidgetContentCommandEvent* aEvent) {
6939 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6939); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 6939; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6940 MOZ_ASSERT(aEvent->mMessage == eContentCommandReplaceText)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mMessage == eContentCommandReplaceText)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aEvent->mMessage == eContentCommandReplaceText)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->mMessage == eContentCommandReplaceText"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6940); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent->mMessage == eContentCommandReplaceText"
")"); do { *((volatile int*)__null) = 6940; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6941 MOZ_DIAGNOSTIC_ASSERT(aEvent->mString.isSome())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent->mString.isSome())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aEvent->mString.isSome())
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aEvent->mString.isSome()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6941); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aEvent->mString.isSome()"
")"); do { *((volatile int*)__null) = 6941; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6942 MOZ_DIAGNOSTIC_ASSERT(!aEvent->mString.ref().IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aEvent->mString.ref().IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aEvent->mString.ref().IsEmpty
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aEvent->mString.ref().IsEmpty()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6942); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!aEvent->mString.ref().IsEmpty()"
")"); do { *((volatile int*)__null) = 6942; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6943
6944 aEvent->mIsEnabled = false;
6945 aEvent->mSucceeded = false;
6946
6947 NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(mPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6947); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
6948
6949 if (XRE_IsParentProcess()) {
6950 // Handle it in focused content process if there is.
6951 if (BrowserParent* remote = BrowserParent::GetFocused()) {
6952 if (!aEvent->mOnlyEnabledCheck) {
6953 Unused << remote->SendReplaceText(*aEvent);
6954 }
6955 // XXX The remote process may be not editable right now. Therefore, this
6956 // may be different from actual state in the remote process.
6957 aEvent->mIsEnabled = true;
6958 aEvent->mSucceeded = true;
6959 return NS_OK;
6960 }
6961 }
6962
6963 // If there is no active editor in this process, we should treat the command
6964 // is disabled.
6965 RefPtr<EditorBase> activeEditor =
6966 nsContentUtils::GetActiveEditor(mPresContext);
6967 if (NS_WARN_IF(!activeEditor)NS_warn_if_impl(!activeEditor, "!activeEditor", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6967)
) {
6968 aEvent->mSucceeded = true;
6969 return NS_OK;
6970 }
6971
6972 RefPtr<TextComposition> composition =
6973 IMEStateManager::GetTextCompositionFor(mPresContext);
6974 if (NS_WARN_IF(composition)NS_warn_if_impl(composition, "composition", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6974)
) {
6975 // We don't support replace text action during composition.
6976 aEvent->mSucceeded = true;
6977 return NS_OK;
6978 }
6979
6980 ContentEventHandler handler(mPresContext);
6981 RefPtr<nsRange> range = handler.GetRangeFromFlatTextOffset(
6982 aEvent, aEvent->mSelection.mOffset,
6983 aEvent->mSelection.mReplaceSrcString.Length());
6984 if (NS_WARN_IF(!range)NS_warn_if_impl(!range, "!range", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6984)
) {
6985 aEvent->mSucceeded = false;
6986 return NS_OK;
6987 }
6988
6989 // If original replacement text isn't matched with selection text, throws
6990 // error.
6991 nsAutoString targetStr;
6992 nsresult rv = handler.GenerateFlatTextContent(range, targetStr);
6993 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 6993)
) {
6994 aEvent->mSucceeded = false;
6995 return NS_OK;
6996 }
6997 if (!aEvent->mSelection.mReplaceSrcString.Equals(targetStr)) {
6998 aEvent->mSucceeded = false;
6999 return NS_OK;
7000 }
7001
7002 rv = activeEditor->ReplaceTextAsAction(
7003 aEvent->mString.ref(), range,
7004 TextEditor::AllowBeforeInputEventCancelable::Yes,
7005 aEvent->mSelection.mPreventSetSelection
7006 ? EditorBase::PreventSetSelection::Yes
7007 : EditorBase::PreventSetSelection::No);
7008 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7008)
) {
7009 aEvent->mSucceeded = false;
7010 return NS_OK;
7011 }
7012
7013 aEvent->mIsEnabled = rv != NS_SUCCESS_DOM_NO_OPERATION;
7014 aEvent->mSucceeded = true;
7015 return NS_OK;
7016}
7017
7018nsresult EventStateManager::DoContentCommandScrollEvent(
7019 WidgetContentCommandEvent* aEvent) {
7020 NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(mPresContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "mPresContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7020); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
7021 PresShell* presShell = mPresContext->GetPresShell();
7022 NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_AVAILABLE)do { if ((__builtin_expect(!!(!(presShell)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "presShell" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7022); return NS_ERROR_NOT_AVAILABLE; } } while (false)
;
7023 NS_ENSURE_TRUE(aEvent->mScroll.mAmount != 0, NS_ERROR_INVALID_ARG)do { if ((__builtin_expect(!!(!(aEvent->mScroll.mAmount !=
0)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE("
"aEvent->mScroll.mAmount != 0" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7023); return NS_ERROR_INVALID_ARG; } } while (false)
;
7024
7025 ScrollUnit scrollUnit;
7026 switch (aEvent->mScroll.mUnit) {
7027 case WidgetContentCommandEvent::eCmdScrollUnit_Line:
7028 scrollUnit = ScrollUnit::LINES;
7029 break;
7030 case WidgetContentCommandEvent::eCmdScrollUnit_Page:
7031 scrollUnit = ScrollUnit::PAGES;
7032 break;
7033 case WidgetContentCommandEvent::eCmdScrollUnit_Whole:
7034 scrollUnit = ScrollUnit::WHOLE;
7035 break;
7036 default:
7037 return NS_ERROR_INVALID_ARG;
7038 }
7039
7040 aEvent->mSucceeded = true;
7041
7042 ScrollContainerFrame* sf =
7043 presShell->GetScrollContainerFrameToScroll(layers::EitherScrollDirection);
7044 aEvent->mIsEnabled =
7045 sf ? (aEvent->mScroll.mIsHorizontal ? WheelHandlingUtils::CanScrollOn(
7046 sf, aEvent->mScroll.mAmount, 0)
7047 : WheelHandlingUtils::CanScrollOn(
7048 sf, 0, aEvent->mScroll.mAmount))
7049 : false;
7050
7051 if (!aEvent->mIsEnabled || aEvent->mOnlyEnabledCheck) {
7052 return NS_OK;
7053 }
7054
7055 nsIntPoint pt(0, 0);
7056 if (aEvent->mScroll.mIsHorizontal) {
7057 pt.x = aEvent->mScroll.mAmount;
7058 } else {
7059 pt.y = aEvent->mScroll.mAmount;
7060 }
7061
7062 // The caller may want synchronous scrolling.
7063 sf->ScrollBy(pt, scrollUnit, ScrollMode::Instant);
7064 return NS_OK;
7065}
7066
7067void EventStateManager::SetActiveManager(EventStateManager* aNewESM,
7068 nsIContent* aContent) {
7069 if (sActiveESM && aNewESM != sActiveESM) {
7070 sActiveESM->SetContentState(nullptr, ElementState::ACTIVE);
7071 }
7072 sActiveESM = aNewESM;
7073 if (sActiveESM && aContent) {
7074 sActiveESM->SetContentState(aContent, ElementState::ACTIVE);
7075 }
7076}
7077
7078void EventStateManager::ClearGlobalActiveContent(EventStateManager* aClearer) {
7079 if (aClearer) {
7080 aClearer->SetContentState(nullptr, ElementState::ACTIVE);
7081 if (sDragOverContent) {
7082 aClearer->SetContentState(nullptr, ElementState::DRAGOVER);
7083 }
7084 }
7085 if (sActiveESM && aClearer != sActiveESM) {
7086 sActiveESM->SetContentState(nullptr, ElementState::ACTIVE);
7087 }
7088 sActiveESM = nullptr;
7089}
7090
7091/******************************************************************/
7092/* mozilla::EventStateManager::DeltaAccumulator */
7093/******************************************************************/
7094
7095void EventStateManager::DeltaAccumulator::InitLineOrPageDelta(
7096 nsIFrame* aTargetFrame, EventStateManager* aESM, WidgetWheelEvent* aEvent) {
7097 MOZ_ASSERT(aESM)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aESM)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(aESM))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aESM", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7097); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aESM" ")");
do { *((volatile int*)__null) = 7097; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7098 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7098); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 7098; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7099
7100 // Reset if the previous wheel event is too old.
7101 if (!mLastTime.IsNull()) {
7102 TimeDuration duration = TimeStamp::Now() - mLastTime;
7103 if (duration.ToMilliseconds() >
7104 StaticPrefs::mousewheel_transaction_timeout()) {
7105 Reset();
7106 }
7107 }
7108 // If we have accumulated delta, we may need to reset it.
7109 if (IsInTransaction()) {
7110 // If wheel event type is changed, reset the values.
7111 if (mHandlingDeltaMode != aEvent->mDeltaMode ||
7112 mIsNoLineOrPageDeltaDevice != aEvent->mIsNoLineOrPageDelta) {
7113 Reset();
7114 } else {
7115 // If the delta direction is changed, we should reset only the
7116 // accumulated values.
7117 if (mX && aEvent->mDeltaX && ((aEvent->mDeltaX > 0.0) != (mX > 0.0))) {
7118 mX = mPendingScrollAmountX = 0.0;
7119 }
7120 if (mY && aEvent->mDeltaY && ((aEvent->mDeltaY > 0.0) != (mY > 0.0))) {
7121 mY = mPendingScrollAmountY = 0.0;
7122 }
7123 }
7124 }
7125
7126 mHandlingDeltaMode = aEvent->mDeltaMode;
7127 mIsNoLineOrPageDeltaDevice = aEvent->mIsNoLineOrPageDelta;
7128
7129 {
7130 ScrollContainerFrame* scrollTarget = aESM->ComputeScrollTarget(
7131 aTargetFrame, aEvent, COMPUTE_DEFAULT_ACTION_TARGET);
7132 nsPresContext* pc = scrollTarget ? scrollTarget->PresContext()
7133 : aTargetFrame->PresContext();
7134 aEvent->mScrollAmount = aESM->GetScrollAmount(pc, aEvent, scrollTarget);
7135 }
7136
7137 // If it's handling neither a device that does not provide line or page deltas
7138 // nor delta values multiplied by prefs, we must not modify lineOrPageDelta
7139 // values.
7140 // TODO(emilio): Does this care about overridden scroll speed?
7141 if (!mIsNoLineOrPageDeltaDevice &&
7142 !EventStateManager::WheelPrefs::GetInstance()
7143 ->NeedToComputeLineOrPageDelta(aEvent)) {
7144 // Set the delta values to mX and mY. They would be used when above block
7145 // resets mX/mY/mPendingScrollAmountX/mPendingScrollAmountY if the direction
7146 // is changed.
7147 // NOTE: We shouldn't accumulate the delta values, it might could cause
7148 // overflow even though it's not a realistic situation.
7149 if (aEvent->mDeltaX) {
7150 mX = aEvent->mDeltaX;
7151 }
7152 if (aEvent->mDeltaY) {
7153 mY = aEvent->mDeltaY;
7154 }
7155 mLastTime = TimeStamp::Now();
7156 return;
7157 }
7158
7159 mX += aEvent->mDeltaX;
7160 mY += aEvent->mDeltaY;
7161
7162 if (mHandlingDeltaMode == WheelEvent_Binding::DOM_DELTA_PIXEL) {
7163 // Records pixel delta values and init mLineOrPageDeltaX and
7164 // mLineOrPageDeltaY for wheel events which are caused by pixel only
7165 // devices. Ignore mouse wheel transaction for computing this. The
7166 // lineOrPageDelta values will be used by dispatching legacy
7167 // eMouseScrollEventClass (DOMMouseScroll) but not be used for scrolling
7168 // of default action. The transaction should be used only for the default
7169 // action.
7170 auto scrollAmountInCSSPixels =
7171 CSSIntSize::FromAppUnitsRounded(aEvent->mScrollAmount);
7172
7173 aEvent->mLineOrPageDeltaX = RoundDown(mX) / scrollAmountInCSSPixels.width;
7174 aEvent->mLineOrPageDeltaY = RoundDown(mY) / scrollAmountInCSSPixels.height;
7175
7176 mX -= aEvent->mLineOrPageDeltaX * scrollAmountInCSSPixels.width;
7177 mY -= aEvent->mLineOrPageDeltaY * scrollAmountInCSSPixels.height;
7178 } else {
7179 aEvent->mLineOrPageDeltaX = RoundDown(mX);
7180 aEvent->mLineOrPageDeltaY = RoundDown(mY);
7181 mX -= aEvent->mLineOrPageDeltaX;
7182 mY -= aEvent->mLineOrPageDeltaY;
7183 }
7184
7185 mLastTime = TimeStamp::Now();
7186}
7187
7188void EventStateManager::DeltaAccumulator::Reset() {
7189 mX = mY = 0.0;
7190 mPendingScrollAmountX = mPendingScrollAmountY = 0.0;
7191 mHandlingDeltaMode = UINT32_MAX(4294967295U);
7192 mIsNoLineOrPageDeltaDevice = false;
7193}
7194
7195nsIntPoint
7196EventStateManager::DeltaAccumulator::ComputeScrollAmountForDefaultAction(
7197 WidgetWheelEvent* aEvent, const nsIntSize& aScrollAmountInDevPixels) {
7198 MOZ_ASSERT(aEvent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aEvent)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aEvent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aEvent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7198); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aEvent" ")"
); do { *((volatile int*)__null) = 7198; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7199
7200 DeltaValues acceleratedDelta = WheelTransaction::AccelerateWheelDelta(aEvent);
7201
7202 nsIntPoint result(0, 0);
7203 if (aEvent->mDeltaMode == WheelEvent_Binding::DOM_DELTA_PIXEL) {
7204 mPendingScrollAmountX += acceleratedDelta.deltaX;
7205 mPendingScrollAmountY += acceleratedDelta.deltaY;
7206 } else {
7207 mPendingScrollAmountX +=
7208 aScrollAmountInDevPixels.width * acceleratedDelta.deltaX;
7209 mPendingScrollAmountY +=
7210 aScrollAmountInDevPixels.height * acceleratedDelta.deltaY;
7211 }
7212 result.x = RoundDown(mPendingScrollAmountX);
7213 result.y = RoundDown(mPendingScrollAmountY);
7214 mPendingScrollAmountX -= result.x;
7215 mPendingScrollAmountY -= result.y;
7216
7217 return result;
7218}
7219
7220/******************************************************************/
7221/* mozilla::EventStateManager::WheelPrefs */
7222/******************************************************************/
7223
7224// static
7225EventStateManager::WheelPrefs* EventStateManager::WheelPrefs::GetInstance() {
7226 if (!sInstance) {
7227 sInstance = new WheelPrefs();
7228 }
7229 return sInstance;
7230}
7231
7232// static
7233void EventStateManager::WheelPrefs::Shutdown() {
7234 delete sInstance;
7235 sInstance = nullptr;
7236}
7237
7238// static
7239void EventStateManager::WheelPrefs::OnPrefChanged(const char* aPrefName,
7240 void* aClosure) {
7241 // forget all prefs, it's not problem for performance.
7242 sInstance->Reset();
7243 DeltaAccumulator::GetInstance()->Reset();
7244}
7245
7246EventStateManager::WheelPrefs::WheelPrefs() {
7247 Reset();
7248 Preferences::RegisterPrefixCallback(OnPrefChanged, "mousewheel.");
7249}
7250
7251EventStateManager::WheelPrefs::~WheelPrefs() {
7252 Preferences::UnregisterPrefixCallback(OnPrefChanged, "mousewheel.");
7253}
7254
7255void EventStateManager::WheelPrefs::Reset() { memset(mInit, 0, sizeof(mInit)); }
7256
7257EventStateManager::WheelPrefs::Index EventStateManager::WheelPrefs::GetIndexFor(
7258 const WidgetWheelEvent* aEvent) {
7259 if (!aEvent) {
7260 return INDEX_DEFAULT;
7261 }
7262
7263 Modifiers modifiers = (aEvent->mModifiers & (MODIFIER_ALT | MODIFIER_CONTROL |
7264 MODIFIER_META | MODIFIER_SHIFT));
7265
7266 switch (modifiers) {
7267 case MODIFIER_ALT:
7268 return INDEX_ALT;
7269 case MODIFIER_CONTROL:
7270 return INDEX_CONTROL;
7271 case MODIFIER_META:
7272 return INDEX_META;
7273 case MODIFIER_SHIFT:
7274 return INDEX_SHIFT;
7275 default:
7276 // If two or more modifier keys are pressed, we should use default
7277 // settings.
7278 return INDEX_DEFAULT;
7279 }
7280}
7281
7282void EventStateManager::WheelPrefs::GetBasePrefName(
7283 EventStateManager::WheelPrefs::Index aIndex, nsACString& aBasePrefName) {
7284 aBasePrefName.AssignLiteral("mousewheel.");
7285 switch (aIndex) {
7286 case INDEX_ALT:
7287 aBasePrefName.AppendLiteral("with_alt.");
7288 break;
7289 case INDEX_CONTROL:
7290 aBasePrefName.AppendLiteral("with_control.");
7291 break;
7292 case INDEX_META:
7293 aBasePrefName.AppendLiteral("with_meta.");
7294 break;
7295 case INDEX_SHIFT:
7296 aBasePrefName.AppendLiteral("with_shift.");
7297 break;
7298 case INDEX_DEFAULT:
7299 default:
7300 aBasePrefName.AppendLiteral("default.");
7301 break;
7302 }
7303}
7304
7305void EventStateManager::WheelPrefs::Init(
7306 EventStateManager::WheelPrefs::Index aIndex) {
7307 if (mInit[aIndex]) {
7308 return;
7309 }
7310 mInit[aIndex] = true;
7311
7312 nsAutoCString basePrefName;
7313 GetBasePrefName(aIndex, basePrefName);
7314
7315 nsAutoCString prefNameX(basePrefName);
7316 prefNameX.AppendLiteral("delta_multiplier_x");
7317 mMultiplierX[aIndex] =
7318 static_cast<double>(Preferences::GetInt(prefNameX.get(), 100)) / 100;
7319
7320 nsAutoCString prefNameY(basePrefName);
7321 prefNameY.AppendLiteral("delta_multiplier_y");
7322 mMultiplierY[aIndex] =
7323 static_cast<double>(Preferences::GetInt(prefNameY.get(), 100)) / 100;
7324
7325 nsAutoCString prefNameZ(basePrefName);
7326 prefNameZ.AppendLiteral("delta_multiplier_z");
7327 mMultiplierZ[aIndex] =
7328 static_cast<double>(Preferences::GetInt(prefNameZ.get(), 100)) / 100;
7329
7330 nsAutoCString prefNameAction(basePrefName);
7331 prefNameAction.AppendLiteral("action");
7332 int32_t action = Preferences::GetInt(prefNameAction.get(), ACTION_SCROLL);
7333 if (action < int32_t(ACTION_NONE) || action > int32_t(ACTION_LAST)) {
7334 NS_WARNING("Unsupported action pref value, replaced with 'Scroll'.")NS_DebugBreak(NS_DEBUG_WARNING, "Unsupported action pref value, replaced with 'Scroll'."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7334)
;
7335 action = ACTION_SCROLL;
7336 }
7337 mActions[aIndex] = static_cast<Action>(action);
7338
7339 // Compute action values overridden by .override_x pref.
7340 // At present, override is possible only for the x-direction
7341 // because this pref is introduced mainly for tilt wheels.
7342 // Note that ACTION_HORIZONTALIZED_SCROLL isn't a valid value for this pref
7343 // because it affects only to deltaY.
7344 prefNameAction.AppendLiteral(".override_x");
7345 int32_t actionOverrideX = Preferences::GetInt(prefNameAction.get(), -1);
7346 if (actionOverrideX < -1 || actionOverrideX > int32_t(ACTION_LAST) ||
7347 actionOverrideX == ACTION_HORIZONTALIZED_SCROLL) {
7348 NS_WARNING("Unsupported action override pref value, didn't override.")NS_DebugBreak(NS_DEBUG_WARNING, "Unsupported action override pref value, didn't override."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/events/EventStateManager.cpp"
, 7348)
;
7349 actionOverrideX = -1;
7350 }
7351 mOverriddenActionsX[aIndex] = (actionOverrideX == -1)
7352 ? static_cast<Action>(action)
7353 : static_cast<Action>(actionOverrideX);
7354}
7355
7356void EventStateManager::WheelPrefs::GetMultiplierForDeltaXAndY(
7357 const WidgetWheelEvent* aEvent, Index aIndex, double* aMultiplierForDeltaX,
7358 double* aMultiplierForDeltaY) {
7359 *aMultiplierForDeltaX = mMultiplierX[aIndex];
7360 *aMultiplierForDeltaY = mMultiplierY[aIndex];
7361 // If the event has been horizontalized(I.e. treated as a horizontal wheel
7362 // scroll for a vertical wheel scroll), then we should swap mMultiplierX and
7363 // mMultiplierY. By doing this, multipliers will still apply to the delta
7364 // values they origianlly corresponded to.
7365 if (aEvent->mDeltaValuesHorizontalizedForDefaultHandler &&
7366 ComputeActionFor(aEvent) == ACTION_HORIZONTALIZED_SCROLL) {
7367 std::swap(*aMultiplierForDeltaX, *aMultiplierForDeltaY);
7368 }
7369}
7370
7371void EventStateManager::WheelPrefs::ApplyUserPrefsToDelta(
7372 WidgetWheelEvent* aEvent) {
7373 if (aEvent->mCustomizedByUserPrefs) {
7374 return;
7375 }
7376
7377 Index index = GetIndexFor(aEvent);
7378 Init(index);
7379
7380 double multiplierForDeltaX = 1.0, multiplierForDeltaY = 1.0;
7381 GetMultiplierForDeltaXAndY(aEvent, index, &multiplierForDeltaX,
7382 &multiplierForDeltaY);
7383 aEvent->mDeltaX *= multiplierForDeltaX;
7384 aEvent->mDeltaY *= multiplierForDeltaY;
7385 aEvent->mDeltaZ *= mMultiplierZ[index];
7386
7387 // If the multiplier is 1.0 or -1.0, i.e., it doesn't change the absolute
7388 // value, we should use lineOrPageDelta values which were set by widget.
7389 // Otherwise, we need to compute them from accumulated delta values.
7390 if (!NeedToComputeLineOrPageDelta(aEvent)) {
7391 aEvent->mLineOrPageDeltaX *= static_cast<int32_t>(multiplierForDeltaX);
7392 aEvent->mLineOrPageDeltaY *= static_cast<int32_t>(multiplierForDeltaY);
7393 } else {
7394 aEvent->mLineOrPageDeltaX = 0;
7395 aEvent->mLineOrPageDeltaY = 0;
7396 }
7397
7398 aEvent->mCustomizedByUserPrefs =
7399 ((mMultiplierX[index] != 1.0) || (mMultiplierY[index] != 1.0) ||
7400 (mMultiplierZ[index] != 1.0));
7401}
7402
7403void EventStateManager::WheelPrefs::CancelApplyingUserPrefsFromOverflowDelta(
7404 WidgetWheelEvent* aEvent) {
7405 Index index = GetIndexFor(aEvent);
7406 Init(index);
7407
7408 // XXX If the multiplier pref value is negative, the scroll direction was
7409 // changed and caused to scroll different direction. In such case,
7410 // this method reverts the sign of overflowDelta. Does it make widget
7411 // happy? Although, widget can know the pref applied delta values by
7412 // referrencing the deltaX and deltaY of the event.
7413
7414 double multiplierForDeltaX = 1.0, multiplierForDeltaY = 1.0;
7415 GetMultiplierForDeltaXAndY(aEvent, index, &multiplierForDeltaX,
7416 &multiplierForDeltaY);
7417 if (multiplierForDeltaX) {
7418 aEvent->mOverflowDeltaX /= multiplierForDeltaX;
7419 }
7420 if (multiplierForDeltaY) {
7421 aEvent->mOverflowDeltaY /= multiplierForDeltaY;
7422 }
7423}
7424
7425EventStateManager::WheelPrefs::Action
7426EventStateManager::WheelPrefs::ComputeActionFor(
7427 const WidgetWheelEvent* aEvent) {
7428 Index index = GetIndexFor(aEvent);
7429 Init(index);
7430
7431 bool deltaXPreferred = (Abs(aEvent->mDeltaX) > Abs(aEvent->mDeltaY) &&
7432 Abs(aEvent->mDeltaX) > Abs(aEvent->mDeltaZ));
7433 Action* actions = deltaXPreferred ? mOverriddenActionsX : mActions;
7434 if (actions[index] == ACTION_NONE || actions[index] == ACTION_SCROLL ||
7435 actions[index] == ACTION_HORIZONTALIZED_SCROLL) {
7436 return actions[index];
7437 }
7438
7439 // Momentum events shouldn't run special actions.
7440 if (aEvent->mIsMomentum) {
7441 // Use the default action. Note that user might kill the wheel scrolling.
7442 Init(INDEX_DEFAULT);
7443 if (actions[INDEX_DEFAULT] == ACTION_SCROLL ||
7444 actions[INDEX_DEFAULT] == ACTION_HORIZONTALIZED_SCROLL) {
7445 return actions[INDEX_DEFAULT];
7446 }
7447 return ACTION_NONE;
7448 }
7449
7450 return actions[index];
7451}
7452
7453bool EventStateManager::WheelPrefs::NeedToComputeLineOrPageDelta(
7454 const WidgetWheelEvent* aEvent) {
7455 Index index = GetIndexFor(aEvent);
7456 Init(index);
7457
7458 return (mMultiplierX[index] != 1.0 && mMultiplierX[index] != -1.0) ||
7459 (mMultiplierY[index] != 1.0 && mMultiplierY[index] != -1.0);
7460}
7461
7462void EventStateManager::WheelPrefs::GetUserPrefsForEvent(
7463 const WidgetWheelEvent* aEvent, double* aOutMultiplierX,
7464 double* aOutMultiplierY) {
7465 Index index = GetIndexFor(aEvent);
7466 Init(index);
7467
7468 double multiplierForDeltaX = 1.0, multiplierForDeltaY = 1.0;
7469 GetMultiplierForDeltaXAndY(aEvent, index, &multiplierForDeltaX,
7470 &multiplierForDeltaY);
7471 *aOutMultiplierX = multiplierForDeltaX;
7472 *aOutMultiplierY = multiplierForDeltaY;
7473}
7474
7475// static
7476Maybe<layers::APZWheelAction> EventStateManager::APZWheelActionFor(
7477 const WidgetWheelEvent* aEvent) {
7478 if (aEvent->mMessage != eWheel) {
7479 return Nothing();
7480 }
7481 WheelPrefs::Action action =
7482 WheelPrefs::GetInstance()->ComputeActionFor(aEvent);
7483 switch (action) {
7484 case WheelPrefs::ACTION_SCROLL:
7485 case WheelPrefs::ACTION_HORIZONTALIZED_SCROLL:
7486 return Some(layers::APZWheelAction::Scroll);
7487 case WheelPrefs::ACTION_PINCH_ZOOM:
7488 return Some(layers::APZWheelAction::PinchZoom);
7489 default:
7490 return Nothing();
7491 }
7492}
7493
7494// static
7495WheelDeltaAdjustmentStrategy EventStateManager::GetWheelDeltaAdjustmentStrategy(
7496 const WidgetWheelEvent& aEvent) {
7497 if (aEvent.mMessage != eWheel) {
7498 return WheelDeltaAdjustmentStrategy::eNone;
7499 }
7500 switch (WheelPrefs::GetInstance()->ComputeActionFor(&aEvent)) {
7501 case WheelPrefs::ACTION_SCROLL:
7502 if (StaticPrefs::mousewheel_autodir_enabled() && 0 == aEvent.mDeltaZ) {
7503 if (StaticPrefs::mousewheel_autodir_honourroot()) {
7504 return WheelDeltaAdjustmentStrategy::eAutoDirWithRootHonour;
7505 }
7506 return WheelDeltaAdjustmentStrategy::eAutoDir;
7507 }
7508 return WheelDeltaAdjustmentStrategy::eNone;
7509 case WheelPrefs::ACTION_HORIZONTALIZED_SCROLL:
7510 return WheelDeltaAdjustmentStrategy::eHorizontalize;
7511 default:
7512 break;
7513 }
7514 return WheelDeltaAdjustmentStrategy::eNone;
7515}
7516
7517void EventStateManager::GetUserPrefsForWheelEvent(
7518 const WidgetWheelEvent* aEvent, double* aOutMultiplierX,
7519 double* aOutMultiplierY) {
7520 WheelPrefs::GetInstance()->GetUserPrefsForEvent(aEvent, aOutMultiplierX,
7521 aOutMultiplierY);
7522}
7523
7524bool EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedX(
7525 const WidgetWheelEvent* aEvent) {
7526 Index index = GetIndexFor(aEvent);
7527 Init(index);
7528 return Abs(mMultiplierX[index]) >=
7529 MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
7530}
7531
7532bool EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedY(
7533 const WidgetWheelEvent* aEvent) {
7534 Index index = GetIndexFor(aEvent);
7535 Init(index);
7536 return Abs(mMultiplierY[index]) >=
7537 MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
7538}
7539
7540} // namespace mozilla

/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 constexpr 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
41.1
Field 'mIsSome' is 0
41.1
Field 'mIsSome' is 0
41.1
Field 'mIsSome' is 0
41.1
Field 'mIsSome' is 0
41.1
Field 'mIsSome' is 0
41.1
Field 'mIsSome' is 0
) {
42
Taking false branch
274 this->addr()->T::~T();
275 }
276 }
43
Calling implicit destructor for 'MaybeStorageBase<mozilla::WidgetMouseEvent, false>'
44
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() {}
45
Calling '~WidgetMouseEvent'
44
45 NonConstT val;
46 } mStorage;
47
48 public:
49 constexpr 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() : empty() {}
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 empty;
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 * Returns true if corresponding DOM event should use fractional coordinates.
262 */
263 [[nodiscard]] bool DOMEventShouldUseFractionalCoords() const;
264};
265
266/******************************************************************************
267 * mozilla::WidgetMouseEvent
268 ******************************************************************************/
269
270class WidgetMouseEvent : public WidgetMouseEventBase,
271 public WidgetPointerHelper {
272 private:
273 friend class dom::PBrowserParent;
274 friend class dom::PBrowserChild;
275 friend class dom::PBrowserBridgeParent;
276 ALLOW_DEPRECATED_READPARAMpublic: enum { kHasDeprecatedReadParamPrivateConstructor = true
}; template <typename, bool> friend class IPC::ReadResult
; private:
277
278 public:
279 typedef bool ReasonType;
280 enum Reason : ReasonType { eReal, eSynthesized };
281
282 typedef uint8_t ContextMenuTriggerType;
283 enum ContextMenuTrigger : ContextMenuTriggerType {
284 eNormal,
285 eContextMenuKey,
286 eControlClick
287 };
288
289 typedef uint8_t ExitFromType;
290 enum ExitFrom : ExitFromType {
291 ePlatformChild,
292 ePlatformTopLevel,
293 ePuppet,
294 ePuppetParentToPuppetChild
295 };
296
297 protected:
298 WidgetMouseEvent() = default;
299
300 WidgetMouseEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget,
301 EventClassID aEventClassID, Reason aReason,
302 ContextMenuTrigger aContextMenuTrigger,
303 const WidgetEventTime* aTime = nullptr)
304 : WidgetMouseEventBase(aIsTrusted, aMessage, aWidget, aEventClassID,
305 aTime),
306 mReason(aReason),
307 mContextMenuTrigger(aContextMenuTrigger) {}
308
309#ifdef DEBUG1
310 void AssertContextMenuEventButtonConsistency() const;
311#endif
312
313 public:
314 virtual WidgetMouseEvent* AsMouseEvent() override { return this; }
315
316 WidgetMouseEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget,
317 Reason aReason = eReal,
318 ContextMenuTrigger aContextMenuTrigger = eNormal,
319 const WidgetEventTime* aTime = nullptr)
320 : WidgetMouseEventBase(aIsTrusted, aMessage, aWidget, eMouseEventClass,
321 aTime),
322 mReason(aReason),
323 mContextMenuTrigger(aContextMenuTrigger) {
324 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"
, 324); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsPointerEventMessage(mMessage)"
")"); do { *((volatile int*)__null) = 324; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
325 if (aMessage == eContextMenu) {
326 mButton = (mContextMenuTrigger == eNormal) ? MouseButton::eSecondary
327 : MouseButton::ePrimary;
328 }
329 }
330
331#ifdef DEBUG1
332 virtual ~WidgetMouseEvent() { AssertContextMenuEventButtonConsistency(); }
46
Calling '~nsCOMPtr'
333#endif
334
335 virtual WidgetEvent* Duplicate() const override {
336 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"
, 337); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClass == eMouseEventClass"
") (" "Duplicate() must be overridden by sub class" ")"); do
{ *((volatile int*)__null) = 337; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
337 "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"
, 337); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClass == eMouseEventClass"
") (" "Duplicate() must be overridden by sub class" ")"); do
{ *((volatile int*)__null) = 337; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
338 // Not copying widget, it is a weak reference.
339 WidgetMouseEvent* result = new WidgetMouseEvent(
340 false, mMessage, nullptr, mReason, mContextMenuTrigger, this);
341 result->AssignMouseEventData(*this, true);
342 result->mFlags = mFlags;
343 return result;
344 }
345
346 // If during mouseup handling we detect that click event might need to be
347 // dispatched, this is setup to be the target of the click event.
348 nsCOMPtr<dom::EventTarget> mClickTarget;
349
350 // mReason indicates the reason why the event is fired:
351 // - Representing mouse operation.
352 // - Synthesized for emulating mousemove event when the content under the
353 // mouse cursor is scrolled.
354 Reason mReason = eReal;
355
356 // mContextMenuTrigger is valid only when mMessage is eContextMenu.
357 // This indicates if the context menu event is caused by context menu key or
358 // other reasons (typically, a click of right mouse button).
359 ContextMenuTrigger mContextMenuTrigger = eNormal;
360
361 // mExitFrom contains a value only when mMessage is eMouseExitFromWidget.
362 // This indicates if the mouse cursor exits from a top level platform widget,
363 // a child widget or a puppet widget.
364 Maybe<ExitFrom> mExitFrom;
365
366 // mClickCount may be non-zero value when mMessage is eMouseDown, eMouseUp,
367 // ePointerClick or eMouseDoubleClick. The number is count of mouse clicks.
368 // Otherwise, this must be 0.
369 uint32_t mClickCount = 0;
370
371 // Whether the event should ignore scroll frame bounds during dispatch.
372 bool mIgnoreRootScrollFrame = false;
373
374 // Whether the event should be dispatched on a target limited in capturing
375 // content.
376 bool mIgnoreCapturingContent = false;
377
378 // Whether the event shouldn't cause click event.
379 bool mClickEventPrevented = false;
380
381 // If this is set to true while the event is being dispatched,
382 // PresShell::EventHandler::FinalizeHandlingEvent will dispatch a synthesized
383 // eMouseMove or ePointerMove.
384 bool mSynthesizeMoveAfterDispatch = false;
385
386 void AssignMouseEventData(const WidgetMouseEvent& aEvent, bool aCopyTargets) {
387 AssignMouseEventBaseData(aEvent, aCopyTargets);
388 AssignPointerHelperData(aEvent, /* aCopyCoalescedEvents */ true);
389
390 mReason = aEvent.mReason;
391 mContextMenuTrigger = aEvent.mContextMenuTrigger;
392 mExitFrom = aEvent.mExitFrom;
393 mClickCount = aEvent.mClickCount;
394 mIgnoreRootScrollFrame = aEvent.mIgnoreRootScrollFrame;
395 mIgnoreCapturingContent = aEvent.mIgnoreCapturingContent;
396 mClickEventPrevented = aEvent.mClickEventPrevented;
397 }
398
399 /**
400 * Returns true if the event is a context menu event caused by key.
401 */
402 bool IsContextMenuKeyEvent() const {
403 return mMessage == eContextMenu && mContextMenuTrigger == eContextMenuKey;
404 }
405
406 /**
407 * Returns true if the event is a real mouse event. Otherwise, i.e., it's
408 * a synthesized event by scroll or something, returns false.
409 */
410 bool IsReal() const { return mReason == eReal; }
411
412 /**
413 * Returns true if middle click paste is enabled.
414 */
415 static bool IsMiddleClickPasteEnabled();
416};
417
418/******************************************************************************
419 * mozilla::WidgetDragEvent
420 ******************************************************************************/
421
422class WidgetDragEvent : public WidgetMouseEvent {
423 private:
424 friend class mozilla::dom::PBrowserParent;
425 friend class mozilla::dom::PBrowserChild;
426 ALLOW_DEPRECATED_READPARAMpublic: enum { kHasDeprecatedReadParamPrivateConstructor = true
}; template <typename, bool> friend class IPC::ReadResult
; private:
427
428 protected:
429 WidgetDragEvent()
430 : mUserCancelled(false),
431 mDefaultPreventedOnContent(false),
432 mInHTMLEditorEventListener(false) {}
433
434 public:
435 virtual WidgetDragEvent* AsDragEvent() override { return this; }
436
437 WidgetDragEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget,
438 const WidgetEventTime* aTime = nullptr)
439 : WidgetMouseEvent(aIsTrusted, aMessage, aWidget, eDragEventClass, eReal,
440 eNormal, aTime),
441 mUserCancelled(false),
442 mDefaultPreventedOnContent(false),
443 mInHTMLEditorEventListener(false) {}
444
445 virtual WidgetEvent* Duplicate() const override {
446 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"
, 447); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClass == eDragEventClass"
") (" "Duplicate() must be overridden by sub class" ")"); do
{ *((volatile int*)__null) = 447; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
447 "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"
, 447); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClass == eDragEventClass"
") (" "Duplicate() must be overridden by sub class" ")"); do
{ *((volatile int*)__null) = 447; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
448 // Not copying widget, it is a weak reference.
449 WidgetDragEvent* result =
450 new WidgetDragEvent(false, mMessage, nullptr, this);
451 result->AssignDragEventData(*this, true);
452 result->mFlags = mFlags;
453 return result;
454 }
455
456 // The dragging data.
457 nsCOMPtr<dom::DataTransfer> mDataTransfer;
458
459 // If this is true, user has cancelled the drag operation.
460 bool mUserCancelled;
461 // If this is true, the drag event's preventDefault() is called on content.
462 bool mDefaultPreventedOnContent;
463 // If this event is currently being handled by HTMLEditorEventListener.
464 bool mInHTMLEditorEventListener;
465
466 // XXX Not tested by test_assign_event_data.html
467 void AssignDragEventData(const WidgetDragEvent& aEvent, bool aCopyTargets) {
468 AssignMouseEventData(aEvent, aCopyTargets);
469
470 mDataTransfer = aEvent.mDataTransfer;
471 // XXX mUserCancelled isn't copied, is this intentionally?
472 mUserCancelled = false;
473 mDefaultPreventedOnContent = aEvent.mDefaultPreventedOnContent;
474 // XXX mInHTMLEditorEventListener isn't copied, is this intentionally?
475 mInHTMLEditorEventListener = false;
476 }
477
478 bool CanConvertToInputData() const {
479 return mMessage == eDragStart || mMessage == eDragEnd ||
480 mMessage == eDragEnter || mMessage == eDragOver ||
481 mMessage == eDragExit || mMessage == eDrop;
482 }
483
484 /**
485 * Should be called before dispatching the DOM tree if this event is
486 * synthesized for tests because drop effect is initialized before
487 * dispatching from widget if it's not synthesized event, but synthesized
488 * events are not initialized in the path.
489 */
490 void InitDropEffectForTests();
491};
492
493/******************************************************************************
494 * mozilla::WidgetMouseScrollEvent
495 *
496 * This is used for legacy DOM mouse scroll events, i.e.,
497 * DOMMouseScroll and MozMousePixelScroll event. These events are NOT hanbled
498 * by ESM even if widget dispatches them. Use new WidgetWheelEvent instead.
499 ******************************************************************************/
500
501class WidgetMouseScrollEvent : public WidgetMouseEventBase {
502 private:
503 WidgetMouseScrollEvent() : mDelta(0), mIsHorizontal(false) {}
504
505 public:
506 virtual WidgetMouseScrollEvent* AsMouseScrollEvent() override { return this; }
507
508 WidgetMouseScrollEvent(bool aIsTrusted, EventMessage aMessage,
509 nsIWidget* aWidget,
510 const WidgetEventTime* aTime = nullptr)
511 : WidgetMouseEventBase(aIsTrusted, aMessage, aWidget,
512 eMouseScrollEventClass, aTime),
513 mDelta(0),
514 mIsHorizontal(false) {}
515
516 virtual WidgetEvent* Duplicate() const override {
517 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"
, 518); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClass == eMouseScrollEventClass"
") (" "Duplicate() must be overridden by sub class" ")"); do
{ *((volatile int*)__null) = 518; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
518 "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"
, 518); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClass == eMouseScrollEventClass"
") (" "Duplicate() must be overridden by sub class" ")"); do
{ *((volatile int*)__null) = 518; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
519 // Not copying widget, it is a weak reference.
520 WidgetMouseScrollEvent* result =
521 new WidgetMouseScrollEvent(false, mMessage, nullptr, this);
522 result->AssignMouseScrollEventData(*this, true);
523 result->mFlags = mFlags;
524 return result;
525 }
526
527 // The delta value of mouse scroll event.
528 // If the event message is eLegacyMouseLineOrPageScroll, the value indicates
529 // scroll amount in lines. However, if the value is
530 // UIEvent::SCROLL_PAGE_UP or UIEvent::SCROLL_PAGE_DOWN, the
531 // value inducates one page scroll. If the event message is
532 // eLegacyMousePixelScroll, the value indicates scroll amount in pixels.
533 int32_t mDelta;
534
535 // If this is true, it may cause to scroll horizontally.
536 // Otherwise, vertically.
537 bool mIsHorizontal;
538
539 void AssignMouseScrollEventData(const WidgetMouseScrollEvent& aEvent,
540 bool aCopyTargets) {
541 AssignMouseEventBaseData(aEvent, aCopyTargets);
542
543 mDelta = aEvent.mDelta;
544 mIsHorizontal = aEvent.mIsHorizontal;
545 }
546};
547
548/******************************************************************************
549 * mozilla::WidgetWheelEvent
550 ******************************************************************************/
551
552class WidgetWheelEvent : public WidgetMouseEventBase {
553 private:
554 friend class mozilla::dom::PBrowserParent;
555 friend class mozilla::dom::PBrowserChild;
556 ALLOW_DEPRECATED_READPARAMpublic: enum { kHasDeprecatedReadParamPrivateConstructor = true
}; template <typename, bool> friend class IPC::ReadResult
; private:
557
558 WidgetWheelEvent()
559 : mDeltaX(0.0),
560 mDeltaY(0.0),
561 mDeltaZ(0.0),
562 mOverflowDeltaX(0.0),
563 mOverflowDeltaY(0.0)
564 // Including WheelEventBinding.h here leads to an include loop, so
565 // we have to hardcode WheelEvent_Binding::DOM_DELTA_PIXEL.
566 ,
567 mDeltaMode(/* WheelEvent_Binding::DOM_DELTA_PIXEL = */ 0),
568 mLineOrPageDeltaX(0),
569 mLineOrPageDeltaY(0),
570 mScrollType(SCROLL_DEFAULT),
571 mCustomizedByUserPrefs(false),
572 mMayHaveMomentum(false),
573 mIsMomentum(false),
574 mIsNoLineOrPageDelta(false),
575 mViewPortIsOverscrolled(false),
576 mCanTriggerSwipe(false),
577 mAllowToOverrideSystemScrollSpeed(false),
578 mDeltaValuesHorizontalizedForDefaultHandler(false) {}
579
580 public:
581 virtual WidgetWheelEvent* AsWheelEvent() override { return this; }
582
583 WidgetWheelEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget,
584 const WidgetEventTime* aTime = nullptr)
585 : WidgetMouseEventBase(aIsTrusted, aMessage, aWidget, eWheelEventClass,
586 aTime),
587 mDeltaX(0.0),
588 mDeltaY(0.0),
589 mDeltaZ(0.0),
590 mOverflowDeltaX(0.0),
591 mOverflowDeltaY(0.0)
592 // Including WheelEventBinding.h here leads to an include loop, so
593 // we have to hardcode WheelEvent_Binding::DOM_DELTA_PIXEL.
594 ,
595 mDeltaMode(/* WheelEvent_Binding::DOM_DELTA_PIXEL = */ 0),
596 mLineOrPageDeltaX(0),
597 mLineOrPageDeltaY(0),
598 mScrollType(SCROLL_DEFAULT),
599 mCustomizedByUserPrefs(false),
600 mMayHaveMomentum(false),
601 mIsMomentum(false),
602 mIsNoLineOrPageDelta(false),
603 mViewPortIsOverscrolled(false),
604 mCanTriggerSwipe(false),
605 mAllowToOverrideSystemScrollSpeed(true),
606 mDeltaValuesHorizontalizedForDefaultHandler(false) {}
607
608 virtual WidgetEvent* Duplicate() const override {
609 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"
, 610); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClass == eWheelEventClass"
") (" "Duplicate() must be overridden by sub class" ")"); do
{ *((volatile int*)__null) = 610; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
610 "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"
, 610); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClass == eWheelEventClass"
") (" "Duplicate() must be overridden by sub class" ")"); do
{ *((volatile int*)__null) = 610; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
611 // Not copying widget, it is a weak reference.
612 WidgetWheelEvent* result =
613 new WidgetWheelEvent(false, mMessage, nullptr, this);
614 result->AssignWheelEventData(*this, true);
615 result->mFlags = mFlags;
616 return result;
617 }
618
619 // Scroll gestures that start at the edge of the scrollable range can result
620 // in a swipe gesture. For the first wheel event of such a gesture, call
621 // TriggersSwipe() after the event has been processed in order to find out
622 // whether a swipe should be started.
623 bool TriggersSwipe() const {
624 return mCanTriggerSwipe && mViewPortIsOverscrolled &&
625 this->mOverflowDeltaX != 0.0;
626 }
627
628 // NOTE: mDeltaX, mDeltaY and mDeltaZ may be customized by
629 // mousewheel.*.delta_multiplier_* prefs which are applied by
630 // EventStateManager. So, after widget dispatches this event,
631 // these delta values may have different values than before.
632 double mDeltaX;
633 double mDeltaY;
634 double mDeltaZ;
635
636 // The mousewheel tick counts.
637 double mWheelTicksX = 0.0;
638 double mWheelTicksY = 0.0;
639
640 enum class DeltaModeCheckingState : uint8_t {
641 // Neither deltaMode nor the delta values have been accessed.
642 Unknown,
643 // The delta values have been accessed, without checking deltaMode first.
644 Unchecked,
645 // The deltaMode has been checked.
646 Checked,
647 };
648
649 // For compat reasons, we might expose a DOM_DELTA_LINE event as
650 // DOM_DELTA_PIXEL instead. Whether we do that depends on whether the event
651 // has been asked for the deltaMode before the deltas. If it has, we assume
652 // that the page will correctly handle DOM_DELTA_LINE. This variable tracks
653 // that state. See bug 1392460.
654 DeltaModeCheckingState mDeltaModeCheckingState =
655 DeltaModeCheckingState::Unknown;
656
657 // The amount of scrolling per line or page, without accounting for mouse
658 // wheel transactions etc.
659 //
660 // Computed by EventStateManager::DeltaAccumulator::InitLineOrPageDelta.
661 nsSize mScrollAmount;
662
663 // overflowed delta values for scroll, these values are set by
664 // EventStateManger. If the default action of the wheel event isn't scroll,
665 // these values are always zero. Otherwise, remaining delta values which are
666 // not used by scroll are set.
667 // NOTE: mDeltaX, mDeltaY and mDeltaZ may be modified by EventStateManager.
668 // However, mOverflowDeltaX and mOverflowDeltaY indicate unused original
669 // delta values which are not applied the delta_multiplier prefs.
670 // So, if widget wanted to know the actual direction to be scrolled,
671 // it would need to check the mDeltaX and mDeltaY.
672 double mOverflowDeltaX;
673 double mOverflowDeltaY;
674
675 // Should be one of WheelEvent_Binding::DOM_DELTA_*
676 uint32_t mDeltaMode;
677
678 // If widget sets mLineOrPageDelta, EventStateManager will dispatch
679 // eLegacyMouseLineOrPageScroll event for compatibility. Note that the delta
680 // value means pages if the mDeltaMode is DOM_DELTA_PAGE, otherwise, lines.
681 int32_t mLineOrPageDeltaX;
682 int32_t mLineOrPageDeltaY;
683
684 // When the default action for an wheel event is moving history or zooming,
685 // need to chose a delta value for doing it.
686 int32_t GetPreferredIntDelta() {
687 if (!mLineOrPageDeltaX && !mLineOrPageDeltaY) {
688 return 0;
689 }
690 if (mLineOrPageDeltaY && !mLineOrPageDeltaX) {
691 return mLineOrPageDeltaY;
692 }
693 if (mLineOrPageDeltaX && !mLineOrPageDeltaY) {
694 return mLineOrPageDeltaX;
695 }
696 if ((mLineOrPageDeltaX < 0 && mLineOrPageDeltaY > 0) ||
697 (mLineOrPageDeltaX > 0 && mLineOrPageDeltaY < 0)) {
698 return 0; // We cannot guess the answer in this case.
699 }
700 return (Abs(mLineOrPageDeltaX) > Abs(mLineOrPageDeltaY))
701 ? mLineOrPageDeltaX
702 : mLineOrPageDeltaY;
703 }
704
705 // Scroll type
706 // The default value is SCROLL_DEFAULT, which means EventStateManager will
707 // select preferred scroll type automatically.
708 enum ScrollType : uint8_t {
709 SCROLL_DEFAULT,
710 SCROLL_SYNCHRONOUSLY,
711 SCROLL_ASYNCHRONOUSLY,
712 SCROLL_SMOOTHLY
713 };
714 ScrollType mScrollType;
715
716 // If the delta values are computed from prefs, this value is true.
717 // Otherwise, i.e., they are computed from native events, false.
718 bool mCustomizedByUserPrefs;
719
720 // true if the momentum events directly tied to this event may follow it.
721 bool mMayHaveMomentum;
722 // true if the event is caused by momentum.
723 bool mIsMomentum;
724
725 // If device event handlers don't know when they should set mLineOrPageDeltaX
726 // and mLineOrPageDeltaY, this is true. Otherwise, false.
727 // If mIsNoLineOrPageDelta is true, ESM will generate
728 // eLegacyMouseLineOrPageScroll events when accumulated delta values reach
729 // a line height.
730 bool mIsNoLineOrPageDelta;
731
732 // Whether or not the parent of the currently overscrolled frame is the
733 // ViewPort. This is false in situations when an element on the page is being
734 // overscrolled (such as a text field), but true when the 'page' is being
735 // overscrolled.
736 bool mViewPortIsOverscrolled;
737
738 // The wheel event can trigger a swipe to start if it's overscrolling the
739 // viewport.
740 bool mCanTriggerSwipe;
741
742 // If mAllowToOverrideSystemScrollSpeed is true, the scroll speed may be
743 // overridden. Otherwise, the scroll speed won't be overridden even if
744 // it's enabled by the pref.
745 bool mAllowToOverrideSystemScrollSpeed;
746
747 // After the event's default action handler has adjusted its delta's values
748 // for horizontalizing a vertical wheel scroll, this variable will be set to
749 // true.
750 bool mDeltaValuesHorizontalizedForDefaultHandler;
751
752 void AssignWheelEventData(const WidgetWheelEvent& aEvent, bool aCopyTargets) {
753 AssignMouseEventBaseData(aEvent, aCopyTargets);
754
755 mDeltaX = aEvent.mDeltaX;
756 mDeltaY = aEvent.mDeltaY;
757 mDeltaZ = aEvent.mDeltaZ;
758 mDeltaMode = aEvent.mDeltaMode;
759 mScrollAmount = aEvent.mScrollAmount;
760 mCustomizedByUserPrefs = aEvent.mCustomizedByUserPrefs;
761 mMayHaveMomentum = aEvent.mMayHaveMomentum;
762 mIsMomentum = aEvent.mIsMomentum;
763 mIsNoLineOrPageDelta = aEvent.mIsNoLineOrPageDelta;
764 mLineOrPageDeltaX = aEvent.mLineOrPageDeltaX;
765 mLineOrPageDeltaY = aEvent.mLineOrPageDeltaY;
766 mScrollType = aEvent.mScrollType;
767 mOverflowDeltaX = aEvent.mOverflowDeltaX;
768 mOverflowDeltaY = aEvent.mOverflowDeltaY;
769 mViewPortIsOverscrolled = aEvent.mViewPortIsOverscrolled;
770 mCanTriggerSwipe = aEvent.mCanTriggerSwipe;
771 mAllowToOverrideSystemScrollSpeed =
772 aEvent.mAllowToOverrideSystemScrollSpeed;
773 mDeltaValuesHorizontalizedForDefaultHandler =
774 aEvent.mDeltaValuesHorizontalizedForDefaultHandler;
775 }
776
777 // System scroll speed settings may be too slow at using Gecko. In such
778 // case, we should override the scroll speed computed with system settings.
779 // Following methods return preferred delta values which are multiplied by
780 // factors specified by prefs. If system scroll speed shouldn't be
781 // overridden (e.g., this feature is disabled by pref), they return raw
782 // delta values.
783 double OverriddenDeltaX() const;
784 double OverriddenDeltaY() const;
785
786 // Compute the overridden delta value. This may be useful for suppressing
787 // too fast scroll by system scroll speed overriding when widget sets
788 // mAllowToOverrideSystemScrollSpeed.
789 static double ComputeOverriddenDelta(double aDelta, bool aIsForVertical);
790
791 private:
792 static bool sInitialized;
793 static bool sIsSystemScrollSpeedOverrideEnabled;
794 static int32_t sOverrideFactorX;
795 static int32_t sOverrideFactorY;
796 static void Initialize();
797};
798
799/******************************************************************************
800 * mozilla::WidgetPointerEvent
801 ******************************************************************************/
802
803class WidgetPointerEvent : public WidgetMouseEvent {
804 friend class mozilla::dom::PBrowserParent;
805 friend class mozilla::dom::PBrowserChild;
806 ALLOW_DEPRECATED_READPARAMpublic: enum { kHasDeprecatedReadParamPrivateConstructor = true
}; template <typename, bool> friend class IPC::ReadResult
; private:
807
808 WidgetPointerEvent() = default;
809
810 public:
811 virtual WidgetPointerEvent* AsPointerEvent() override { return this; }
812
813 WidgetPointerEvent(bool aIsTrusted, EventMessage aMsg, nsIWidget* w,
814 const WidgetEventTime* aTime)
815 : WidgetMouseEvent(aIsTrusted, aMsg, w, ePointerEventClass, eReal,
816 eNormal, aTime) {
817 if (aMsg == eContextMenu) {
818 mButton = (mContextMenuTrigger == eNormal) ? MouseButton::eSecondary
819 : MouseButton::ePrimary;
820 }
821 }
822
823 WidgetPointerEvent(bool aIsTrusted, EventMessage aMsg, nsIWidget* w,
824 ContextMenuTrigger aContextMenuTrigger = eNormal,
825 const WidgetEventTime* aTime = nullptr)
826 : WidgetMouseEvent(aIsTrusted, aMsg, w, ePointerEventClass, eReal,
827 aContextMenuTrigger, aTime) {
828 if (aMsg == eContextMenu) {
829 mButton = (mContextMenuTrigger == eNormal) ? MouseButton::eSecondary
830 : MouseButton::ePrimary;
831 }
832 }
833
834 explicit WidgetPointerEvent(const WidgetMouseEvent& aEvent)
835 : WidgetMouseEvent(aEvent) {
836 mClass = ePointerEventClass;
837 }
838
839 virtual WidgetEvent* Duplicate() const override {
840 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"
, 841); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClass == ePointerEventClass"
") (" "Duplicate() must be overridden by sub class" ")"); do
{ *((volatile int*)__null) = 841; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
841 "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"
, 841); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClass == ePointerEventClass"
") (" "Duplicate() must be overridden by sub class" ")"); do
{ *((volatile int*)__null) = 841; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
842 // Not copying widget, it is a weak reference.
843 WidgetPointerEvent* result = new WidgetPointerEvent(
844 false, mMessage, nullptr, mContextMenuTrigger, this);
845 result->AssignPointerEventData(*this, true);
846 result->mFlags = mFlags;
847 return result;
848 }
849
850 double mWidth = 1.0;
851 double mHeight = 1.0;
852 bool mIsPrimary = true;
853 bool mFromTouchEvent = false;
854
855 // XXX Not tested by test_assign_event_data.html
856 void AssignPointerEventData(const WidgetPointerEvent& aEvent,
857 bool aCopyTargets) {
858 AssignMouseEventData(aEvent, aCopyTargets);
859
860 mWidth = aEvent.mWidth;
861 mHeight = aEvent.mHeight;
862 mIsPrimary = aEvent.mIsPrimary;
863 mFromTouchEvent = aEvent.mFromTouchEvent;
864 }
865};
866
867} // namespace mozilla
868
869#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));
47
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___)