Bug Summary

File:root/firefox-clang/dom/events/EventStateManager.cpp
Warning:line 2109, column 11
Access to field 'mMessage' results in a dereference of a null pointer (loaded from variable 'mouseEvent')

Annotated Source Code

Press '?' to see keyboard shortcuts

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