Bug Summary

File:root/firefox-clang/dom/events/EventStateManager.cpp
Warning:line 5232, column 22
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name EventStateManager.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/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)
;
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)
;
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)
;
2067
2068 BrowserParent* remote = aRemoteTarget;
2069
2070 WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
2071 bool isContextMenuKey = mouseEvent && mouseEvent->IsContextMenuKeyEvent();
2072 if (aEvent->mClass == eKeyboardEventClass || isContextMenuKey) {
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()) {
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)
;
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)
;
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) {
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) {
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)
;
1
Assuming 'aPresContext' is non-null
2
Taking false branch
3
Loop condition is false. Exiting loop
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)
;
4
Assuming 'aStatus' is non-null
5
Taking false branch
6
Loop condition is false. Exiting loop
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 &&
7
Assuming the condition is false
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) {
8
Control jumps to 'case ePointerUp:' at line 4198
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)
;
9
Assuming 'pointerEvent' is non-null
10
Taking false branch
11
Loop condition is false. Exiting loop
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 (
14
Taking true branch
4207 // After pointercancel, pointer becomes invalid so we can remove
4208 // relevant helper from table.
4209 pointerEvent->mMessage == ePointerCancel ||
12
Assuming field 'mMessage' is not equal to 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()) {
13
Assuming the condition is true
4214 GenerateMouseEnterExit(pointerEvent);
15
Calling 'EventStateManager::GenerateMouseEnterExit'
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)
63
Taking false branch
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() &&
64
Loop condition is false. Exiting loop
65
Assuming the condition is true
66
Taking true branch
5218 (aMessage
65.1
'aMessage' is not equal to eMouseLeave
== eMouseLeave || aMessage
65.2
'aMessage' is not equal to eMouseEnter
== eMouseEnter ||
5219 aMessage
65.3
'aMessage' is not equal to eMouseOver
== eMouseOver || aMessage
65.4
'aMessage' is equal to eMouseOut
== eMouseOut)) {
5220 mCurrentTargetContent = nullptr;
5221 nsCOMPtr<Element> pointerLockedElement =
5222 PointerLockManager::GetLockedElement();
5223 if (!pointerLockedElement) {
67
Taking false branch
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 =
68
'pointerLockedFrame' initialized here
5228 mPresContext->GetPrimaryFrameFor(pointerLockedElement);
5229 if (NS_WARN_IF(!pointerLockedFrame)NS_warn_if_impl(!pointerLockedFrame, "!pointerLockedFrame", "/root/firefox-clang/dom/events/EventStateManager.cpp"
, 5229)
) {
69
Assuming 'pointerLockedFrame' is null
70
Assuming the condition is false
71
Taking false branch
5230 return nullptr;
5231 }
5232 return do_AddRef(pointerLockedFrame->GetNearestWidget());
72
Called C++ object pointer is null
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;
23
Assuming field 'mClass' is not equal to ePointerEventClass
42
Assuming field 'mClass' is not equal to ePointerEventClass
5361 LogModule* const logModule =
5362 isPointer
23.1
'isPointer' is false
42.1
'isPointer' is false
? sPointerBoundaryLog : sMouseBoundaryLog;
24
'?' condition is false
43
'?' condition is false
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()) {
25
Assuming the condition is false
26
Taking false branch
44
Assuming the condition is false
45
Taking false branch
5370 return;
5371 }
5372 // Before firing "out" and/or "leave" events, check for recursion
5373 if (wrapper->IsDispatchingOutEventOnLastOverEventTarget()) {
27
Taking false branch
46
Taking false branch
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)
28
Assuming the condition is false
29
Taking true branch
30
'?' condition is false
31
Loop condition is false. Exiting loop
47
Assuming the condition is false
48
Taking true branch
49
'?' condition is false
50
Loop condition is false. Exiting loop
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 =
32
Taking true branch
51
Taking false branch
5389 do_QueryObject(wrapper->GetDeepestLeaveEventTarget())) {
5390 if (BrowsingContext* bc = flo->GetExtantBrowsingContext()) {
33
Assuming 'bc' is non-null
34
Taking true branch
5391 if (nsIDocShell* docshell = bc->GetDocShell()) {
35
Assuming 'docshell' is non-null
36
Taking true branch
5392 if (RefPtr<nsPresContext> presContext = docshell->GetPresContext()) {
37
Taking true branch
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)
38
Assuming the condition is false
39
Taking true branch
40
Loop condition is false. Exiting loop
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);
41
Calling 'EventStateManager::NotifyMouseOut'
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()) {
52
Taking false branch
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
52.1
'aMovingInto' is null
&& !isPointer
52.2
'isPointer' is false
) {
53
Taking true branch
5417 // Unset :hover
5418 SetContentState(nullptr, ElementState::HOVER);
5419 }
5420
5421 EnterLeaveDispatcher leaveDispatcher(
5422 this, wrapper->GetDeepestLeaveEventTarget(), aMovingInto, aMouseEvent,
5423 isPointer
53.1
'isPointer' is false
? ePointerLeave : eMouseLeave);
54
'?' condition is false
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()) {
55
Taking true branch
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)
56
Assuming the condition is false
57
Taking true branch
58
'?' condition is false
59
'?' condition is true
60
Loop condition is false. Exiting loop
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(
62
Calling 'EventStateManager::DispatchMouseOrPointerBoundaryEvent'
5434 aMouseEvent, isPointer
60.1
'isPointer' is false
? ePointerOut : eMouseOut, outEventTarget,
61
'?' condition is false
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;
16
Taking false branch
5672
5673 // Hold onto old target content through the event and reset after.
5674 nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
5675
5676 switch (aMouseEvent->mMessage) {
17
Control jumps to 'case ePointerUp:' at line 5695
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) {
18
Assuming field 'mDispatchedAtLeastOnce' is true
19
Taking true branch
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()) {
20
Assuming the condition is true
21
Taking true branch
5702 NotifyMouseOut(aMouseEvent, nullptr);
22
Calling 'EventStateManager::NotifyMouseOut'
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