Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp
Warning:line 3345, column 11
Value stored to 'startFrame' is never read

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 Unified_cpp_dom_base9.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/base -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/base -resource-dir /usr/lib/llvm-19/lib/clang/19 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /var/lib/jenkins/workspace/firefox-scan-build/dom/base -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dom/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/battery -I /var/lib/jenkins/workspace/firefox-scan-build/dom/events -I /var/lib/jenkins/workspace/firefox-scan-build/dom/media -I /var/lib/jenkins/workspace/firefox-scan-build/dom/network -I /var/lib/jenkins/workspace/firefox-scan-build/caps -I /var/lib/jenkins/workspace/firefox-scan-build/docshell/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/base -I /var/lib/jenkins/workspace/firefox-scan-build/dom/file -I /var/lib/jenkins/workspace/firefox-scan-build/dom/geolocation -I /var/lib/jenkins/workspace/firefox-scan-build/dom/html -I /var/lib/jenkins/workspace/firefox-scan-build/dom/ipc -I /var/lib/jenkins/workspace/firefox-scan-build/dom/storage -I /var/lib/jenkins/workspace/firefox-scan-build/dom/svg -I /var/lib/jenkins/workspace/firefox-scan-build/dom/xml -I /var/lib/jenkins/workspace/firefox-scan-build/dom/xslt/xpath -I /var/lib/jenkins/workspace/firefox-scan-build/dom/xul -I /var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/src -I /var/lib/jenkins/workspace/firefox-scan-build/gfx/2d -I /var/lib/jenkins/workspace/firefox-scan-build/image -I /var/lib/jenkins/workspace/firefox-scan-build/js/xpconnect/loader -I /var/lib/jenkins/workspace/firefox-scan-build/js/xpconnect/src -I /var/lib/jenkins/workspace/firefox-scan-build/js/xpconnect/wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/layout/base -I /var/lib/jenkins/workspace/firefox-scan-build/layout/forms -I /var/lib/jenkins/workspace/firefox-scan-build/layout/generic -I /var/lib/jenkins/workspace/firefox-scan-build/layout/style -I /var/lib/jenkins/workspace/firefox-scan-build/layout/xul -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/base -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/url-classifier -I /var/lib/jenkins/workspace/firefox-scan-build/parser/htmlparser -I /var/lib/jenkins/workspace/firefox-scan-build/security/manager/ssl -I /var/lib/jenkins/workspace/firefox-scan-build/third_party/xsimd/include -I /var/lib/jenkins/workspace/firefox-scan-build/widget -I /var/lib/jenkins/workspace/firefox-scan-build/xpcom/build -I /var/lib/jenkins/workspace/firefox-scan-build/xpcom/ds -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/sctp/datachannel -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /var/lib/jenkins/workspace/firefox-scan-build/ipc/chromium/src -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gtk-3.0/unix-print -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-09-22-115206-3586786-1 -x c++ Unified_cpp_dom_base9.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 "mozilla/dom/BrowserParent.h"
8
9#include "nsFocusManager.h"
10
11#include "LayoutConstants.h"
12#include "ChildIterator.h"
13#include "nsIInterfaceRequestorUtils.h"
14#include "nsGkAtoms.h"
15#include "nsContentUtils.h"
16#include "ContentParent.h"
17#include "nsPIDOMWindow.h"
18#include "nsIContentInlines.h"
19#include "nsIDocShell.h"
20#include "nsIDocShellTreeOwner.h"
21#include "nsIFormControl.h"
22#include "nsLayoutUtils.h"
23#include "nsFrameTraversal.h"
24#include "nsIWebNavigation.h"
25#include "nsCaret.h"
26#include "nsIBaseWindow.h"
27#include "nsIAppWindow.h"
28#include "nsTextControlFrame.h"
29#include "nsThreadUtils.h"
30#include "nsViewManager.h"
31#include "nsFrameSelection.h"
32#include "mozilla/dom/Selection.h"
33#include "nsXULPopupManager.h"
34#include "nsMenuPopupFrame.h"
35#include "nsIScriptError.h"
36#include "nsIScriptObjectPrincipal.h"
37#include "nsIPrincipal.h"
38#include "nsIObserverService.h"
39#include "BrowserChild.h"
40#include "nsFrameLoader.h"
41#include "nsHTMLDocument.h"
42#include "nsNetUtil.h"
43#include "nsRange.h"
44#include "nsFrameLoaderOwner.h"
45#include "nsQueryObject.h"
46#include "nsIXULRuntime.h"
47
48#include "mozilla/AccessibleCaretEventHub.h"
49#include "mozilla/ContentEvents.h"
50#include "mozilla/FocusModel.h"
51#include "mozilla/dom/ContentChild.h"
52#include "mozilla/dom/Document.h"
53#include "mozilla/dom/DocumentInlines.h"
54#include "mozilla/dom/Element.h"
55#include "mozilla/dom/ElementBinding.h"
56#include "mozilla/dom/HTMLImageElement.h"
57#include "mozilla/dom/HTMLInputElement.h"
58#include "mozilla/dom/HTMLSlotElement.h"
59#include "mozilla/dom/HTMLAreaElement.h"
60#include "mozilla/dom/BrowserBridgeChild.h"
61#include "mozilla/dom/Text.h"
62#include "mozilla/dom/XULPopupElement.h"
63#include "mozilla/dom/WindowGlobalParent.h"
64#include "mozilla/dom/WindowGlobalChild.h"
65#include "mozilla/EventDispatcher.h"
66#include "mozilla/EventStateManager.h"
67#include "mozilla/HTMLEditor.h"
68#include "mozilla/IMEStateManager.h"
69#include "mozilla/LookAndFeel.h"
70#include "mozilla/Maybe.h"
71#include "mozilla/PointerLockManager.h"
72#include "mozilla/Preferences.h"
73#include "mozilla/PresShell.h"
74#include "mozilla/Services.h"
75#include "mozilla/Unused.h"
76#include "mozilla/StaticPrefs_full_screen_api.h"
77#include "mozilla/Try.h"
78#include "mozilla/widget/IMEData.h"
79#include <algorithm>
80
81#include "nsIDOMXULMenuListElement.h"
82
83#ifdef ACCESSIBILITY1
84# include "nsAccessibilityService.h"
85#endif
86
87using namespace mozilla;
88using namespace mozilla::dom;
89using namespace mozilla::widget;
90
91// Two types of focus pr logging are available:
92// 'Focus' for normal focus manager calls
93// 'FocusNavigation' for tab and document navigation
94LazyLogModule gFocusLog("Focus");
95LazyLogModule gFocusNavigationLog("FocusNavigation");
96
97#define LOGFOCUS(args)do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, MOZ_LOG_EXPAND_ARGS
args); } } while (0)
MOZ_LOG(gFocusLog, mozilla::LogLevel::Debug, args)do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, MOZ_LOG_EXPAND_ARGS
args); } } while (0)
98#define LOGFOCUSNAVIGATION(args)do { const ::mozilla::LogModule* moz_real_module = gFocusNavigationLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, MOZ_LOG_EXPAND_ARGS
args); } } while (0)
\
99 MOZ_LOG(gFocusNavigationLog, mozilla::LogLevel::Debug, args)do { const ::mozilla::LogModule* moz_real_module = gFocusNavigationLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, MOZ_LOG_EXPAND_ARGS
args); } } while (0)
100
101#define LOGTAG(log, format, content)if ((__builtin_expect(!!(mozilla::detail::log_test(log, LogLevel
::Debug)), 0))) { nsAutoCString tag("(none)"_ns); if (content
) { content->NodeInfo()->NameAtom()->ToUTF8String(tag
); } do { const ::mozilla::LogModule* moz_real_module = log; if
((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, format, tag.get()); } } while (0); }
\
102 if (MOZ_LOG_TEST(log, LogLevel::Debug)(__builtin_expect(!!(mozilla::detail::log_test(log, LogLevel::
Debug)), 0))
) { \
103 nsAutoCString tag("(none)"_ns); \
104 if (content) { \
105 content->NodeInfo()->NameAtom()->ToUTF8String(tag); \
106 } \
107 MOZ_LOG(log, LogLevel::Debug, (format, tag.get()))do { const ::mozilla::LogModule* moz_real_module = log; if ((
__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, format, tag.get()); } } while (0)
; \
108 }
109
110#define LOGCONTENT(format, content)if ((__builtin_expect(!!(mozilla::detail::log_test(gFocusLog,
LogLevel::Debug)), 0))) { nsAutoCString tag("(none)"_ns); if
(content) { content->NodeInfo()->NameAtom()->ToUTF8String
(tag); } do { const ::mozilla::LogModule* moz_real_module = gFocusLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, format, tag.get()); } } while (0); }
LOGTAG(gFocusLog, format, content)if ((__builtin_expect(!!(mozilla::detail::log_test(gFocusLog,
LogLevel::Debug)), 0))) { nsAutoCString tag("(none)"_ns); if
(content) { content->NodeInfo()->NameAtom()->ToUTF8String
(tag); } do { const ::mozilla::LogModule* moz_real_module = gFocusLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, format, tag.get()); } } while (0); }
111#define LOGCONTENTNAVIGATION(format, content)if ((__builtin_expect(!!(mozilla::detail::log_test(gFocusNavigationLog
, LogLevel::Debug)), 0))) { nsAutoCString tag("(none)"_ns); if
(content) { content->NodeInfo()->NameAtom()->ToUTF8String
(tag); } do { const ::mozilla::LogModule* moz_real_module = gFocusNavigationLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, format, tag.get()); } } while (0); }
\
112 LOGTAG(gFocusNavigationLog, format, content)if ((__builtin_expect(!!(mozilla::detail::log_test(gFocusNavigationLog
, LogLevel::Debug)), 0))) { nsAutoCString tag("(none)"_ns); if
(content) { content->NodeInfo()->NameAtom()->ToUTF8String
(tag); } do { const ::mozilla::LogModule* moz_real_module = gFocusNavigationLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, format, tag.get()); } } while (0); }
113
114struct nsDelayedBlurOrFocusEvent {
115 nsDelayedBlurOrFocusEvent(EventMessage aEventMessage, PresShell* aPresShell,
116 Document* aDocument, EventTarget* aTarget,
117 EventTarget* aRelatedTarget)
118 : mPresShell(aPresShell),
119 mDocument(aDocument),
120 mTarget(aTarget),
121 mEventMessage(aEventMessage),
122 mRelatedTarget(aRelatedTarget) {}
123
124 nsDelayedBlurOrFocusEvent(const nsDelayedBlurOrFocusEvent& aOther)
125 : mPresShell(aOther.mPresShell),
126 mDocument(aOther.mDocument),
127 mTarget(aOther.mTarget),
128 mEventMessage(aOther.mEventMessage) {}
129
130 RefPtr<PresShell> mPresShell;
131 nsCOMPtr<Document> mDocument;
132 nsCOMPtr<EventTarget> mTarget;
133 EventMessage mEventMessage;
134 nsCOMPtr<EventTarget> mRelatedTarget;
135};
136
137inline void ImplCycleCollectionUnlink(nsDelayedBlurOrFocusEvent& aField) {
138 aField.mPresShell = nullptr;
139 aField.mDocument = nullptr;
140 aField.mTarget = nullptr;
141 aField.mRelatedTarget = nullptr;
142}
143
144inline void ImplCycleCollectionTraverse(
145 nsCycleCollectionTraversalCallback& aCallback,
146 nsDelayedBlurOrFocusEvent& aField, const char* aName, uint32_t aFlags = 0) {
147 CycleCollectionNoteChild(
148 aCallback, static_cast<nsIDocumentObserver*>(aField.mPresShell.get()),
149 aName, aFlags);
150 CycleCollectionNoteChild(aCallback, aField.mDocument.get(), aName, aFlags);
151 CycleCollectionNoteChild(aCallback, aField.mTarget.get(), aName, aFlags);
152 CycleCollectionNoteChild(aCallback, aField.mRelatedTarget.get(), aName,
153 aFlags);
154}
155
156NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFocusManager)nsresult nsFocusManager::QueryInterface(const nsIID& aIID
, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 156); MOZ_PretendNoReturn(); } } while (0); nsISupports* foundInterface
; if (TopThreeWordsEquals( aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID), (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID)) && (LowWordEquals(aIID, (nsXPCOMCycleCollectionParticipant
::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>::
kIID)) || LowWordEquals(aIID, (nsCycleCollectionISupports::COMTypeInfo
<nsCycleCollectionISupports, void>::kIID)))) { if (LowWordEquals
(aIID, (nsXPCOMCycleCollectionParticipant::COMTypeInfo<nsXPCOMCycleCollectionParticipant
, void>::kIID))) { *aInstancePtr = nsFocusManager::cycleCollection
::GetParticipant(); return NS_OK; } if (LowWordEquals(aIID, (
nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports
, void>::kIID))) { *aInstancePtr = nsFocusManager::cycleCollection
::Upcast(this); return NS_OK; } foundInterface = nullptr; } else
157 NS_INTERFACE_MAP_ENTRY(nsIFocusManager)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIFocusManager>)) foundInterface
= static_cast<nsIFocusManager*>(this); else
158 NS_INTERFACE_MAP_ENTRY(nsIObserver)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIObserver>)) foundInterface = static_cast
<nsIObserver*>(this); else
159 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupportsWeakReference>)) foundInterface
= static_cast<nsISupportsWeakReference*>(this); else
160 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIFocusManager)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupports>)) foundInterface = static_cast
<nsISupports*>(static_cast<nsIFocusManager*>(this
)); else
161NS_INTERFACE_MAP_ENDfoundInterface = 0; nsresult status; if (!foundInterface) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(!aIID.Equals((nsISupports::COMTypeInfo<nsISupports
, void>::kIID)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aIID.Equals((nsISupports::COMTypeInfo
<nsISupports, void>::kIID))))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 161); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))"
")"); do { *((volatile int*)__null) = 161; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); status = NS_NOINTERFACE
; } else { (foundInterface)->AddRef(); status = NS_OK; } *
aInstancePtr = foundInterface; return status; }
162
163NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFocusManager)MozExternalRefCountType nsFocusManager::AddRef(void) { static_assert
(!std::is_destructible_v<nsFocusManager>, "Reference-counted class "
"nsFocusManager" " should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 163); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
163; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); _mOwningThread.AssertOwnership("nsFocusManager"
" not thread-safe"); nsISupports* base = nsFocusManager::cycleCollection
::Upcast(this); nsrefcnt count = mRefCnt.incr(base); NS_LogAddRef
((this), (count), ("nsFocusManager"), (uint32_t)(sizeof(*this
))); return count; }
164NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFocusManager)MozExternalRefCountType nsFocusManager::Release(void) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 164); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 164
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); _mOwningThread.AssertOwnership("nsFocusManager" " not thread-safe"
); nsISupports* base = nsFocusManager::cycleCollection::Upcast
(this); nsrefcnt count = mRefCnt.decr(base); NS_LogRelease((this
), (count), ("nsFocusManager")); return count; } void nsFocusManager
::DeleteCycleCollectable(void) { delete (this); }
165
166NS_IMPL_CYCLE_COLLECTION_WEAK(nsFocusManager, mActiveWindow,nsFocusManager::cycleCollection nsFocusManager::_cycleCollectorGlobal
; void nsFocusManager::cycleCollection::Unlink(void* p) { nsFocusManager
* tmp = DowncastCCParticipant<nsFocusManager>(p); ImplCycleCollectionUnlink
(tmp->mActiveWindow); ImplCycleCollectionUnlink(tmp->mActiveBrowsingContextInContent
); ImplCycleCollectionUnlink(tmp->mActiveBrowsingContextInChrome
); ImplCycleCollectionUnlink(tmp->mFocusedWindow); ImplCycleCollectionUnlink
(tmp->mFocusedBrowsingContextInContent); ImplCycleCollectionUnlink
(tmp->mFocusedBrowsingContextInChrome); ImplCycleCollectionUnlink
(tmp->mFocusedElement); ImplCycleCollectionUnlink(tmp->
mFirstBlurEvent); ImplCycleCollectionUnlink(tmp->mFirstFocusEvent
); ImplCycleCollectionUnlink(tmp->mWindowBeingLowered); ImplCycleCollectionUnlink
(tmp->mDelayedBlurFocusEvents); tmp->ClearWeakReferences
(); (void)tmp; } nsresult nsFocusManager::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { nsFocusManager
* tmp = DowncastCCParticipant<nsFocusManager>(p); cb.DescribeRefCountedNode
(tmp->mRefCnt.get(), "nsFocusManager"); ImplCycleCollectionTraverse
(cb, tmp->mActiveWindow, "mActiveWindow", 0); ImplCycleCollectionTraverse
(cb, tmp->mActiveBrowsingContextInContent, "mActiveBrowsingContextInContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveBrowsingContextInChrome
, "mActiveBrowsingContextInChrome", 0); ImplCycleCollectionTraverse
(cb, tmp->mFocusedWindow, "mFocusedWindow", 0); ImplCycleCollectionTraverse
(cb, tmp->mFocusedBrowsingContextInContent, "mFocusedBrowsingContextInContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mFocusedBrowsingContextInChrome
, "mFocusedBrowsingContextInChrome", 0); ImplCycleCollectionTraverse
(cb, tmp->mFocusedElement, "mFocusedElement", 0); ImplCycleCollectionTraverse
(cb, tmp->mFirstBlurEvent, "mFirstBlurEvent", 0); ImplCycleCollectionTraverse
(cb, tmp->mFirstFocusEvent, "mFirstFocusEvent", 0); ImplCycleCollectionTraverse
(cb, tmp->mWindowBeingLowered, "mWindowBeingLowered", 0); ImplCycleCollectionTraverse
(cb, tmp->mDelayedBlurFocusEvents, "mDelayedBlurFocusEvents"
, 0); (void)tmp; return NS_OK; }
167 mActiveBrowsingContextInContent,nsFocusManager::cycleCollection nsFocusManager::_cycleCollectorGlobal
; void nsFocusManager::cycleCollection::Unlink(void* p) { nsFocusManager
* tmp = DowncastCCParticipant<nsFocusManager>(p); ImplCycleCollectionUnlink
(tmp->mActiveWindow); ImplCycleCollectionUnlink(tmp->mActiveBrowsingContextInContent
); ImplCycleCollectionUnlink(tmp->mActiveBrowsingContextInChrome
); ImplCycleCollectionUnlink(tmp->mFocusedWindow); ImplCycleCollectionUnlink
(tmp->mFocusedBrowsingContextInContent); ImplCycleCollectionUnlink
(tmp->mFocusedBrowsingContextInChrome); ImplCycleCollectionUnlink
(tmp->mFocusedElement); ImplCycleCollectionUnlink(tmp->
mFirstBlurEvent); ImplCycleCollectionUnlink(tmp->mFirstFocusEvent
); ImplCycleCollectionUnlink(tmp->mWindowBeingLowered); ImplCycleCollectionUnlink
(tmp->mDelayedBlurFocusEvents); tmp->ClearWeakReferences
(); (void)tmp; } nsresult nsFocusManager::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { nsFocusManager
* tmp = DowncastCCParticipant<nsFocusManager>(p); cb.DescribeRefCountedNode
(tmp->mRefCnt.get(), "nsFocusManager"); ImplCycleCollectionTraverse
(cb, tmp->mActiveWindow, "mActiveWindow", 0); ImplCycleCollectionTraverse
(cb, tmp->mActiveBrowsingContextInContent, "mActiveBrowsingContextInContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveBrowsingContextInChrome
, "mActiveBrowsingContextInChrome", 0); ImplCycleCollectionTraverse
(cb, tmp->mFocusedWindow, "mFocusedWindow", 0); ImplCycleCollectionTraverse
(cb, tmp->mFocusedBrowsingContextInContent, "mFocusedBrowsingContextInContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mFocusedBrowsingContextInChrome
, "mFocusedBrowsingContextInChrome", 0); ImplCycleCollectionTraverse
(cb, tmp->mFocusedElement, "mFocusedElement", 0); ImplCycleCollectionTraverse
(cb, tmp->mFirstBlurEvent, "mFirstBlurEvent", 0); ImplCycleCollectionTraverse
(cb, tmp->mFirstFocusEvent, "mFirstFocusEvent", 0); ImplCycleCollectionTraverse
(cb, tmp->mWindowBeingLowered, "mWindowBeingLowered", 0); ImplCycleCollectionTraverse
(cb, tmp->mDelayedBlurFocusEvents, "mDelayedBlurFocusEvents"
, 0); (void)tmp; return NS_OK; }
168 mActiveBrowsingContextInChrome, mFocusedWindow,nsFocusManager::cycleCollection nsFocusManager::_cycleCollectorGlobal
; void nsFocusManager::cycleCollection::Unlink(void* p) { nsFocusManager
* tmp = DowncastCCParticipant<nsFocusManager>(p); ImplCycleCollectionUnlink
(tmp->mActiveWindow); ImplCycleCollectionUnlink(tmp->mActiveBrowsingContextInContent
); ImplCycleCollectionUnlink(tmp->mActiveBrowsingContextInChrome
); ImplCycleCollectionUnlink(tmp->mFocusedWindow); ImplCycleCollectionUnlink
(tmp->mFocusedBrowsingContextInContent); ImplCycleCollectionUnlink
(tmp->mFocusedBrowsingContextInChrome); ImplCycleCollectionUnlink
(tmp->mFocusedElement); ImplCycleCollectionUnlink(tmp->
mFirstBlurEvent); ImplCycleCollectionUnlink(tmp->mFirstFocusEvent
); ImplCycleCollectionUnlink(tmp->mWindowBeingLowered); ImplCycleCollectionUnlink
(tmp->mDelayedBlurFocusEvents); tmp->ClearWeakReferences
(); (void)tmp; } nsresult nsFocusManager::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { nsFocusManager
* tmp = DowncastCCParticipant<nsFocusManager>(p); cb.DescribeRefCountedNode
(tmp->mRefCnt.get(), "nsFocusManager"); ImplCycleCollectionTraverse
(cb, tmp->mActiveWindow, "mActiveWindow", 0); ImplCycleCollectionTraverse
(cb, tmp->mActiveBrowsingContextInContent, "mActiveBrowsingContextInContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveBrowsingContextInChrome
, "mActiveBrowsingContextInChrome", 0); ImplCycleCollectionTraverse
(cb, tmp->mFocusedWindow, "mFocusedWindow", 0); ImplCycleCollectionTraverse
(cb, tmp->mFocusedBrowsingContextInContent, "mFocusedBrowsingContextInContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mFocusedBrowsingContextInChrome
, "mFocusedBrowsingContextInChrome", 0); ImplCycleCollectionTraverse
(cb, tmp->mFocusedElement, "mFocusedElement", 0); ImplCycleCollectionTraverse
(cb, tmp->mFirstBlurEvent, "mFirstBlurEvent", 0); ImplCycleCollectionTraverse
(cb, tmp->mFirstFocusEvent, "mFirstFocusEvent", 0); ImplCycleCollectionTraverse
(cb, tmp->mWindowBeingLowered, "mWindowBeingLowered", 0); ImplCycleCollectionTraverse
(cb, tmp->mDelayedBlurFocusEvents, "mDelayedBlurFocusEvents"
, 0); (void)tmp; return NS_OK; }
169 mFocusedBrowsingContextInContent,nsFocusManager::cycleCollection nsFocusManager::_cycleCollectorGlobal
; void nsFocusManager::cycleCollection::Unlink(void* p) { nsFocusManager
* tmp = DowncastCCParticipant<nsFocusManager>(p); ImplCycleCollectionUnlink
(tmp->mActiveWindow); ImplCycleCollectionUnlink(tmp->mActiveBrowsingContextInContent
); ImplCycleCollectionUnlink(tmp->mActiveBrowsingContextInChrome
); ImplCycleCollectionUnlink(tmp->mFocusedWindow); ImplCycleCollectionUnlink
(tmp->mFocusedBrowsingContextInContent); ImplCycleCollectionUnlink
(tmp->mFocusedBrowsingContextInChrome); ImplCycleCollectionUnlink
(tmp->mFocusedElement); ImplCycleCollectionUnlink(tmp->
mFirstBlurEvent); ImplCycleCollectionUnlink(tmp->mFirstFocusEvent
); ImplCycleCollectionUnlink(tmp->mWindowBeingLowered); ImplCycleCollectionUnlink
(tmp->mDelayedBlurFocusEvents); tmp->ClearWeakReferences
(); (void)tmp; } nsresult nsFocusManager::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { nsFocusManager
* tmp = DowncastCCParticipant<nsFocusManager>(p); cb.DescribeRefCountedNode
(tmp->mRefCnt.get(), "nsFocusManager"); ImplCycleCollectionTraverse
(cb, tmp->mActiveWindow, "mActiveWindow", 0); ImplCycleCollectionTraverse
(cb, tmp->mActiveBrowsingContextInContent, "mActiveBrowsingContextInContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveBrowsingContextInChrome
, "mActiveBrowsingContextInChrome", 0); ImplCycleCollectionTraverse
(cb, tmp->mFocusedWindow, "mFocusedWindow", 0); ImplCycleCollectionTraverse
(cb, tmp->mFocusedBrowsingContextInContent, "mFocusedBrowsingContextInContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mFocusedBrowsingContextInChrome
, "mFocusedBrowsingContextInChrome", 0); ImplCycleCollectionTraverse
(cb, tmp->mFocusedElement, "mFocusedElement", 0); ImplCycleCollectionTraverse
(cb, tmp->mFirstBlurEvent, "mFirstBlurEvent", 0); ImplCycleCollectionTraverse
(cb, tmp->mFirstFocusEvent, "mFirstFocusEvent", 0); ImplCycleCollectionTraverse
(cb, tmp->mWindowBeingLowered, "mWindowBeingLowered", 0); ImplCycleCollectionTraverse
(cb, tmp->mDelayedBlurFocusEvents, "mDelayedBlurFocusEvents"
, 0); (void)tmp; return NS_OK; }
170 mFocusedBrowsingContextInChrome, mFocusedElement,nsFocusManager::cycleCollection nsFocusManager::_cycleCollectorGlobal
; void nsFocusManager::cycleCollection::Unlink(void* p) { nsFocusManager
* tmp = DowncastCCParticipant<nsFocusManager>(p); ImplCycleCollectionUnlink
(tmp->mActiveWindow); ImplCycleCollectionUnlink(tmp->mActiveBrowsingContextInContent
); ImplCycleCollectionUnlink(tmp->mActiveBrowsingContextInChrome
); ImplCycleCollectionUnlink(tmp->mFocusedWindow); ImplCycleCollectionUnlink
(tmp->mFocusedBrowsingContextInContent); ImplCycleCollectionUnlink
(tmp->mFocusedBrowsingContextInChrome); ImplCycleCollectionUnlink
(tmp->mFocusedElement); ImplCycleCollectionUnlink(tmp->
mFirstBlurEvent); ImplCycleCollectionUnlink(tmp->mFirstFocusEvent
); ImplCycleCollectionUnlink(tmp->mWindowBeingLowered); ImplCycleCollectionUnlink
(tmp->mDelayedBlurFocusEvents); tmp->ClearWeakReferences
(); (void)tmp; } nsresult nsFocusManager::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { nsFocusManager
* tmp = DowncastCCParticipant<nsFocusManager>(p); cb.DescribeRefCountedNode
(tmp->mRefCnt.get(), "nsFocusManager"); ImplCycleCollectionTraverse
(cb, tmp->mActiveWindow, "mActiveWindow", 0); ImplCycleCollectionTraverse
(cb, tmp->mActiveBrowsingContextInContent, "mActiveBrowsingContextInContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveBrowsingContextInChrome
, "mActiveBrowsingContextInChrome", 0); ImplCycleCollectionTraverse
(cb, tmp->mFocusedWindow, "mFocusedWindow", 0); ImplCycleCollectionTraverse
(cb, tmp->mFocusedBrowsingContextInContent, "mFocusedBrowsingContextInContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mFocusedBrowsingContextInChrome
, "mFocusedBrowsingContextInChrome", 0); ImplCycleCollectionTraverse
(cb, tmp->mFocusedElement, "mFocusedElement", 0); ImplCycleCollectionTraverse
(cb, tmp->mFirstBlurEvent, "mFirstBlurEvent", 0); ImplCycleCollectionTraverse
(cb, tmp->mFirstFocusEvent, "mFirstFocusEvent", 0); ImplCycleCollectionTraverse
(cb, tmp->mWindowBeingLowered, "mWindowBeingLowered", 0); ImplCycleCollectionTraverse
(cb, tmp->mDelayedBlurFocusEvents, "mDelayedBlurFocusEvents"
, 0); (void)tmp; return NS_OK; }
171 mFirstBlurEvent, mFirstFocusEvent,nsFocusManager::cycleCollection nsFocusManager::_cycleCollectorGlobal
; void nsFocusManager::cycleCollection::Unlink(void* p) { nsFocusManager
* tmp = DowncastCCParticipant<nsFocusManager>(p); ImplCycleCollectionUnlink
(tmp->mActiveWindow); ImplCycleCollectionUnlink(tmp->mActiveBrowsingContextInContent
); ImplCycleCollectionUnlink(tmp->mActiveBrowsingContextInChrome
); ImplCycleCollectionUnlink(tmp->mFocusedWindow); ImplCycleCollectionUnlink
(tmp->mFocusedBrowsingContextInContent); ImplCycleCollectionUnlink
(tmp->mFocusedBrowsingContextInChrome); ImplCycleCollectionUnlink
(tmp->mFocusedElement); ImplCycleCollectionUnlink(tmp->
mFirstBlurEvent); ImplCycleCollectionUnlink(tmp->mFirstFocusEvent
); ImplCycleCollectionUnlink(tmp->mWindowBeingLowered); ImplCycleCollectionUnlink
(tmp->mDelayedBlurFocusEvents); tmp->ClearWeakReferences
(); (void)tmp; } nsresult nsFocusManager::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { nsFocusManager
* tmp = DowncastCCParticipant<nsFocusManager>(p); cb.DescribeRefCountedNode
(tmp->mRefCnt.get(), "nsFocusManager"); ImplCycleCollectionTraverse
(cb, tmp->mActiveWindow, "mActiveWindow", 0); ImplCycleCollectionTraverse
(cb, tmp->mActiveBrowsingContextInContent, "mActiveBrowsingContextInContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveBrowsingContextInChrome
, "mActiveBrowsingContextInChrome", 0); ImplCycleCollectionTraverse
(cb, tmp->mFocusedWindow, "mFocusedWindow", 0); ImplCycleCollectionTraverse
(cb, tmp->mFocusedBrowsingContextInContent, "mFocusedBrowsingContextInContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mFocusedBrowsingContextInChrome
, "mFocusedBrowsingContextInChrome", 0); ImplCycleCollectionTraverse
(cb, tmp->mFocusedElement, "mFocusedElement", 0); ImplCycleCollectionTraverse
(cb, tmp->mFirstBlurEvent, "mFirstBlurEvent", 0); ImplCycleCollectionTraverse
(cb, tmp->mFirstFocusEvent, "mFirstFocusEvent", 0); ImplCycleCollectionTraverse
(cb, tmp->mWindowBeingLowered, "mWindowBeingLowered", 0); ImplCycleCollectionTraverse
(cb, tmp->mDelayedBlurFocusEvents, "mDelayedBlurFocusEvents"
, 0); (void)tmp; return NS_OK; }
172 mWindowBeingLowered, mDelayedBlurFocusEvents)nsFocusManager::cycleCollection nsFocusManager::_cycleCollectorGlobal
; void nsFocusManager::cycleCollection::Unlink(void* p) { nsFocusManager
* tmp = DowncastCCParticipant<nsFocusManager>(p); ImplCycleCollectionUnlink
(tmp->mActiveWindow); ImplCycleCollectionUnlink(tmp->mActiveBrowsingContextInContent
); ImplCycleCollectionUnlink(tmp->mActiveBrowsingContextInChrome
); ImplCycleCollectionUnlink(tmp->mFocusedWindow); ImplCycleCollectionUnlink
(tmp->mFocusedBrowsingContextInContent); ImplCycleCollectionUnlink
(tmp->mFocusedBrowsingContextInChrome); ImplCycleCollectionUnlink
(tmp->mFocusedElement); ImplCycleCollectionUnlink(tmp->
mFirstBlurEvent); ImplCycleCollectionUnlink(tmp->mFirstFocusEvent
); ImplCycleCollectionUnlink(tmp->mWindowBeingLowered); ImplCycleCollectionUnlink
(tmp->mDelayedBlurFocusEvents); tmp->ClearWeakReferences
(); (void)tmp; } nsresult nsFocusManager::cycleCollection::TraverseNative
( void* p, nsCycleCollectionTraversalCallback& cb) { nsFocusManager
* tmp = DowncastCCParticipant<nsFocusManager>(p); cb.DescribeRefCountedNode
(tmp->mRefCnt.get(), "nsFocusManager"); ImplCycleCollectionTraverse
(cb, tmp->mActiveWindow, "mActiveWindow", 0); ImplCycleCollectionTraverse
(cb, tmp->mActiveBrowsingContextInContent, "mActiveBrowsingContextInContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mActiveBrowsingContextInChrome
, "mActiveBrowsingContextInChrome", 0); ImplCycleCollectionTraverse
(cb, tmp->mFocusedWindow, "mFocusedWindow", 0); ImplCycleCollectionTraverse
(cb, tmp->mFocusedBrowsingContextInContent, "mFocusedBrowsingContextInContent"
, 0); ImplCycleCollectionTraverse(cb, tmp->mFocusedBrowsingContextInChrome
, "mFocusedBrowsingContextInChrome", 0); ImplCycleCollectionTraverse
(cb, tmp->mFocusedElement, "mFocusedElement", 0); ImplCycleCollectionTraverse
(cb, tmp->mFirstBlurEvent, "mFirstBlurEvent", 0); ImplCycleCollectionTraverse
(cb, tmp->mFirstFocusEvent, "mFirstFocusEvent", 0); ImplCycleCollectionTraverse
(cb, tmp->mWindowBeingLowered, "mWindowBeingLowered", 0); ImplCycleCollectionTraverse
(cb, tmp->mDelayedBlurFocusEvents, "mDelayedBlurFocusEvents"
, 0); (void)tmp; return NS_OK; }
173
174StaticRefPtr<nsFocusManager> nsFocusManager::sInstance;
175bool nsFocusManager::sTestMode = false;
176uint64_t nsFocusManager::sFocusActionCounter = 0;
177
178static const char* kObservedPrefs[] = {"accessibility.browsewithcaret",
179 "focusmanager.testmode", nullptr};
180
181nsFocusManager::nsFocusManager()
182 : mActionIdForActiveBrowsingContextInContent(0),
183 mActionIdForActiveBrowsingContextInChrome(0),
184 mActionIdForFocusedBrowsingContextInContent(0),
185 mActionIdForFocusedBrowsingContextInChrome(0),
186 mActiveBrowsingContextInContentSetFromOtherProcess(false),
187 mEventHandlingNeedsFlush(false) {}
188
189nsFocusManager::~nsFocusManager() {
190 Preferences::UnregisterCallbacks(nsFocusManager::PrefChanged, kObservedPrefs,
191 this);
192
193 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
194 if (obs) {
195 obs->RemoveObserver(this, "xpcom-shutdown");
196 }
197}
198
199// static
200nsresult nsFocusManager::Init() {
201 sInstance = new nsFocusManager();
202
203 sTestMode = Preferences::GetBool("focusmanager.testmode", false);
204
205 Preferences::RegisterCallbacks(nsFocusManager::PrefChanged, kObservedPrefs,
206 sInstance.get());
207
208 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
209 if (obs) {
210 obs->AddObserver(sInstance, "xpcom-shutdown", true);
211 }
212
213 return NS_OK;
214}
215
216// static
217void nsFocusManager::Shutdown() { sInstance = nullptr; }
218
219// static
220void nsFocusManager::PrefChanged(const char* aPref, void* aSelf) {
221 if (RefPtr<nsFocusManager> fm = static_cast<nsFocusManager*>(aSelf)) {
222 fm->PrefChanged(aPref);
223 }
224}
225
226void nsFocusManager::PrefChanged(const char* aPref) {
227 nsDependentCString pref(aPref);
228 if (pref.EqualsLiteral("accessibility.browsewithcaret")) {
229 UpdateCaretForCaretBrowsingMode();
230 } else if (pref.EqualsLiteral("focusmanager.testmode")) {
231 sTestMode = Preferences::GetBool("focusmanager.testmode", false);
232 }
233}
234
235NS_IMETHODIMPnsresult
236nsFocusManager::Observe(nsISupports* aSubject, const char* aTopic,
237 const char16_t* aData) {
238 if (!nsCRT::strcmp(aTopic, "xpcom-shutdown")) {
239 mActiveWindow = nullptr;
240 mActiveBrowsingContextInContent = nullptr;
241 mActionIdForActiveBrowsingContextInContent = 0;
242 mActionIdForFocusedBrowsingContextInContent = 0;
243 mActiveBrowsingContextInChrome = nullptr;
244 mActionIdForActiveBrowsingContextInChrome = 0;
245 mActionIdForFocusedBrowsingContextInChrome = 0;
246 mFocusedWindow = nullptr;
247 mFocusedBrowsingContextInContent = nullptr;
248 mFocusedBrowsingContextInChrome = nullptr;
249 mFocusedElement = nullptr;
250 mFirstBlurEvent = nullptr;
251 mFirstFocusEvent = nullptr;
252 mWindowBeingLowered = nullptr;
253 mDelayedBlurFocusEvents.Clear();
254 }
255
256 return NS_OK;
257}
258
259static bool ActionIdComparableAndLower(uint64_t aActionId,
260 uint64_t aReference) {
261 MOZ_ASSERT(aActionId, "Uninitialized action id")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aActionId)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aActionId))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aActionId" " (" "Uninitialized action id"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 261); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aActionId" ") ("
"Uninitialized action id" ")"); do { *((volatile int*)__null
) = 261; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
262 auto [actionProc, actionId] =
263 nsContentUtils::SplitProcessSpecificId(aActionId);
264 auto [refProc, refId] = nsContentUtils::SplitProcessSpecificId(aReference);
265 return actionProc == refProc && actionId < refId;
266}
267
268// given a frame content node, retrieve the nsIDOMWindow displayed in it
269static nsPIDOMWindowOuter* GetContentWindow(nsIContent* aContent) {
270 Document* doc = aContent->GetComposedDoc();
271 if (doc) {
272 Document* subdoc = doc->GetSubDocumentFor(aContent);
273 if (subdoc) {
274 return subdoc->GetWindow();
275 }
276 }
277
278 return nullptr;
279}
280
281bool nsFocusManager::IsFocused(nsIContent* aContent) {
282 if (!aContent || !mFocusedElement) {
283 return false;
284 }
285 return aContent == mFocusedElement;
286}
287
288bool nsFocusManager::IsTestMode() { return sTestMode; }
289
290bool nsFocusManager::IsInActiveWindow(BrowsingContext* aBC) const {
291 RefPtr<BrowsingContext> top = aBC->Top();
292 if (XRE_IsParentProcess()) {
293 top = top->Canonical()->TopCrossChromeBoundary();
294 }
295 return IsSameOrAncestor(top, GetActiveBrowsingContext());
296}
297
298// get the current window for the given content node
299static nsPIDOMWindowOuter* GetCurrentWindow(nsIContent* aContent) {
300 Document* doc = aContent->GetComposedDoc();
301 return doc ? doc->GetWindow() : nullptr;
302}
303
304// static
305Element* nsFocusManager::GetFocusedDescendant(
306 nsPIDOMWindowOuter* aWindow, SearchRange aSearchRange,
307 nsPIDOMWindowOuter** aFocusedWindow) {
308 NS_ENSURE_TRUE(aWindow, nullptr)do { if ((__builtin_expect(!!(!(aWindow)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aWindow" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 308); return nullptr; } } while (false)
;
309
310 *aFocusedWindow = nullptr;
311
312 Element* currentElement = nullptr;
313 nsPIDOMWindowOuter* window = aWindow;
314 for (;;) {
315 *aFocusedWindow = window;
316 currentElement = window->GetFocusedElement();
317 if (!currentElement || aSearchRange == eOnlyCurrentWindow) {
318 break;
319 }
320
321 window = GetContentWindow(currentElement);
322 if (!window) {
323 break;
324 }
325
326 if (aSearchRange == eIncludeAllDescendants) {
327 continue;
328 }
329
330 MOZ_ASSERT(aSearchRange == eIncludeVisibleDescendants)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSearchRange == eIncludeVisibleDescendants)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aSearchRange == eIncludeVisibleDescendants))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aSearchRange == eIncludeVisibleDescendants"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 330); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSearchRange == eIncludeVisibleDescendants"
")"); do { *((volatile int*)__null) = 330; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
331
332 // If the child window doesn't have PresShell, it means the window is
333 // invisible.
334 nsIDocShell* docShell = window->GetDocShell();
335 if (!docShell) {
336 break;
337 }
338 if (!docShell->GetPresShell()) {
339 break;
340 }
341 }
342
343 NS_IF_ADDREF(*aFocusedWindow)ns_if_addref(*aFocusedWindow);
344
345 return currentElement;
346}
347
348// static
349InputContextAction::Cause nsFocusManager::GetFocusMoveActionCause(
350 uint32_t aFlags) {
351 if (aFlags & nsIFocusManager::FLAG_BYTOUCH) {
352 return InputContextAction::CAUSE_TOUCH;
353 } else if (aFlags & nsIFocusManager::FLAG_BYMOUSE) {
354 return InputContextAction::CAUSE_MOUSE;
355 } else if (aFlags & nsIFocusManager::FLAG_BYKEY) {
356 return InputContextAction::CAUSE_KEY;
357 } else if (aFlags & nsIFocusManager::FLAG_BYLONGPRESS) {
358 return InputContextAction::CAUSE_LONGPRESS;
359 }
360 return InputContextAction::CAUSE_UNKNOWN;
361}
362
363NS_IMETHODIMPnsresult
364nsFocusManager::GetActiveWindow(mozIDOMWindowProxy** aWindow) {
365 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()"
" (" "Must not be called outside the parent process." ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 366); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
") (" "Must not be called outside the parent process." ")");
do { *((volatile int*)__null) = 366; __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
366 "Must not be called outside the parent process.")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()"
" (" "Must not be called outside the parent process." ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 366); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
") (" "Must not be called outside the parent process." ")");
do { *((volatile int*)__null) = 366; __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
367 NS_IF_ADDREF(*aWindow = mActiveWindow)ns_if_addref(*aWindow = mActiveWindow);
368 return NS_OK;
369}
370
371NS_IMETHODIMPnsresult
372nsFocusManager::GetActiveBrowsingContext(BrowsingContext** aBrowsingContext) {
373 NS_IF_ADDREF(*aBrowsingContext = GetActiveBrowsingContext())ns_if_addref(*aBrowsingContext = GetActiveBrowsingContext());
374 return NS_OK;
375}
376
377void nsFocusManager::FocusWindow(nsPIDOMWindowOuter* aWindow,
378 CallerType aCallerType) {
379 if (RefPtr<nsFocusManager> fm = sInstance) {
380 fm->SetFocusedWindowWithCallerType(aWindow, aCallerType);
381 }
382}
383
384NS_IMETHODIMPnsresult
385nsFocusManager::GetFocusedWindow(mozIDOMWindowProxy** aFocusedWindow) {
386 NS_IF_ADDREF(*aFocusedWindow = mFocusedWindow)ns_if_addref(*aFocusedWindow = mFocusedWindow);
387 return NS_OK;
388}
389
390NS_IMETHODIMPnsresult
391nsFocusManager::GetFocusedContentBrowsingContext(
392 BrowsingContext** aBrowsingContext) {
393 MOZ_DIAGNOSTIC_ASSERT(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()"
" (" "We only have use cases for this in the parent process"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 395); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsParentProcess()"
") (" "We only have use cases for this in the parent process"
")"); do { *((volatile int*)__null) = 395; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
394 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()"
" (" "We only have use cases for this in the parent process"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 395); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsParentProcess()"
") (" "We only have use cases for this in the parent process"
")"); do { *((volatile int*)__null) = 395; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
395 "We only have use cases for this in the parent process")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()"
" (" "We only have use cases for this in the parent process"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 395); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsParentProcess()"
") (" "We only have use cases for this in the parent process"
")"); do { *((volatile int*)__null) = 395; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
396 NS_IF_ADDREF(*aBrowsingContext = GetFocusedBrowsingContextInChrome())ns_if_addref(*aBrowsingContext = GetFocusedBrowsingContextInChrome
())
;
397 return NS_OK;
398}
399
400NS_IMETHODIMPnsresult
401nsFocusManager::GetActiveContentBrowsingContext(
402 BrowsingContext** aBrowsingContext) {
403 MOZ_DIAGNOSTIC_ASSERT(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()"
" (" "We only have use cases for this in the parent process"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 405); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsParentProcess()"
") (" "We only have use cases for this in the parent process"
")"); do { *((volatile int*)__null) = 405; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
404 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()"
" (" "We only have use cases for this in the parent process"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 405); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsParentProcess()"
") (" "We only have use cases for this in the parent process"
")"); do { *((volatile int*)__null) = 405; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
405 "We only have use cases for this in the parent process")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()"
" (" "We only have use cases for this in the parent process"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 405); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "XRE_IsParentProcess()"
") (" "We only have use cases for this in the parent process"
")"); do { *((volatile int*)__null) = 405; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
406 NS_IF_ADDREF(*aBrowsingContext = GetActiveBrowsingContextInChrome())ns_if_addref(*aBrowsingContext = GetActiveBrowsingContextInChrome
())
;
407 return NS_OK;
408}
409
410nsresult nsFocusManager::SetFocusedWindowWithCallerType(
411 mozIDOMWindowProxy* aWindowToFocus, CallerType aCallerType) {
412 LOGFOCUS(("<<SetFocusedWindow begin>>"))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "<<SetFocusedWindow begin>>"
); } } while (0)
;
413
414 nsCOMPtr<nsPIDOMWindowOuter> windowToFocus =
415 nsPIDOMWindowOuter::From(aWindowToFocus);
416 NS_ENSURE_TRUE(windowToFocus, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(windowToFocus)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "windowToFocus" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 416); return NS_ERROR_FAILURE; } } while (false)
;
417
418 nsCOMPtr<Element> frameElement = windowToFocus->GetFrameElementInternal();
419 Maybe<uint64_t> existingActionId;
420 if (frameElement) {
421 // pass false for aFocusChanged so that the caret does not get updated
422 // and scrolling does not occur.
423 existingActionId = SetFocusInner(frameElement, 0, false, true);
424 } else if (auto* bc = windowToFocus->GetBrowsingContext();
425 bc && !bc->IsTop()) {
426 // No frameElement means windowToFocus is an OOP iframe, so
427 // the above SetFocusInner is not called. That means the focus
428 // of the currently focused BC is not going to be cleared. So
429 // we do that manually here.
430 if (RefPtr<BrowsingContext> focusedBC = GetFocusedBrowsingContext()) {
431 // If focusedBC is an ancestor of bc, blur will be handled
432 // correctly by nsFocusManager::AdjustWindowFocus.
433 if (!IsSameOrAncestor(focusedBC, bc)) {
434 existingActionId.emplace(sInstance->GenerateFocusActionId());
435 Blur(focusedBC, nullptr, true, true, false, existingActionId.value());
436 }
437 }
438 } else {
439 // this is a top-level window. If the window has a child frame focused,
440 // clear the focus. Otherwise, focus should already be in this frame, or
441 // already cleared. This ensures that focus will be in this frame and not
442 // in a child.
443 nsIContent* content = windowToFocus->GetFocusedElement();
444 if (content) {
445 if (nsCOMPtr<nsPIDOMWindowOuter> childWindow = GetContentWindow(content))
446 ClearFocus(windowToFocus);
447 }
448 }
449
450 nsCOMPtr<nsPIDOMWindowOuter> rootWindow = windowToFocus->GetPrivateRoot();
451 const uint64_t actionId = existingActionId.isSome()
452 ? existingActionId.value()
453 : sInstance->GenerateFocusActionId();
454 if (rootWindow) {
455 RaiseWindow(rootWindow, aCallerType, actionId);
456 }
457
458 LOGFOCUS(("<<SetFocusedWindow end actionid: %" PRIu64 ">>", actionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "<<SetFocusedWindow end actionid: %"
"l" "u" ">>", actionId); } } while (0)
;
459
460 return NS_OK;
461}
462
463NS_IMETHODIMPnsresult nsFocusManager::SetFocusedWindow(
464 mozIDOMWindowProxy* aWindowToFocus) {
465 return SetFocusedWindowWithCallerType(aWindowToFocus, CallerType::System);
466}
467
468NS_IMETHODIMPnsresult
469nsFocusManager::GetFocusedElement(Element** aFocusedElement) {
470 RefPtr<Element> focusedElement = mFocusedElement;
471 focusedElement.forget(aFocusedElement);
472 return NS_OK;
473}
474
475uint32_t nsFocusManager::GetLastFocusMethod(nsPIDOMWindowOuter* aWindow) const {
476 nsPIDOMWindowOuter* window = aWindow ? aWindow : mFocusedWindow.get();
477 uint32_t method = window ? window->GetFocusMethod() : 0;
478 NS_ASSERTION((method & METHOD_MASK) == method, "invalid focus method")do { if (!((method & METHOD_MASK) == method)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "invalid focus method", "(method & METHOD_MASK) == method"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 478); MOZ_PretendNoReturn(); } } while (0)
;
479 return method;
480}
481
482NS_IMETHODIMPnsresult
483nsFocusManager::GetLastFocusMethod(mozIDOMWindowProxy* aWindow,
484 uint32_t* aLastFocusMethod) {
485 *aLastFocusMethod = GetLastFocusMethod(nsPIDOMWindowOuter::From(aWindow));
486 return NS_OK;
487}
488
489NS_IMETHODIMPnsresult
490nsFocusManager::SetFocus(Element* aElement, uint32_t aFlags) {
491 LOGFOCUS(("<<SetFocus begin>>"))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "<<SetFocus begin>>"
); } } while (0)
;
492
493 NS_ENSURE_ARG(aElement)do { if ((__builtin_expect(!!(!(aElement)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aElement" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 493); return NS_ERROR_INVALID_ARG; } } while (false)
;
494
495 SetFocusInner(aElement, aFlags, true, true);
496
497 LOGFOCUS(("<<SetFocus end>>"))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "<<SetFocus end>>"
); } } while (0)
;
498
499 return NS_OK;
500}
501
502NS_IMETHODIMPnsresult
503nsFocusManager::ElementIsFocusable(Element* aElement, uint32_t aFlags,
504 bool* aIsFocusable) {
505 NS_ENSURE_TRUE(aElement, NS_ERROR_INVALID_ARG)do { if ((__builtin_expect(!!(!(aElement)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aElement" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 505); return NS_ERROR_INVALID_ARG; } } while (false)
;
506 *aIsFocusable = !!FlushAndCheckIfFocusable(aElement, aFlags);
507 return NS_OK;
508}
509
510MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMPnsresult
511nsFocusManager::MoveFocus(mozIDOMWindowProxy* aWindow, Element* aStartElement,
512 uint32_t aType, uint32_t aFlags, Element** aElement) {
513 *aElement = nullptr;
514
515 LOGFOCUS(("<<MoveFocus begin Type: %d Flags: %x>>", aType, aFlags))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "<<MoveFocus begin Type: %d Flags: %x>>"
, aType, aFlags); } } while (0)
;
516
517 if (MOZ_LOG_TEST(gFocusLog, LogLevel::Debug)(__builtin_expect(!!(mozilla::detail::log_test(gFocusLog, LogLevel
::Debug)), 0))
&& mFocusedWindow) {
518 Document* doc = mFocusedWindow->GetExtantDoc();
519 if (doc && doc->GetDocumentURI()) {
520 LOGFOCUS((" Focused Window: %p %s", mFocusedWindow.get(),do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Focused Window: %p %s"
, mFocusedWindow.get(), doc->GetDocumentURI()->GetSpecOrDefault
().get()); } } while (0)
521 doc->GetDocumentURI()->GetSpecOrDefault().get()))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Focused Window: %p %s"
, mFocusedWindow.get(), doc->GetDocumentURI()->GetSpecOrDefault
().get()); } } while (0)
;
522 }
523 }
524
525 LOGCONTENT(" Current Focus: %s", mFocusedElement.get())if ((__builtin_expect(!!(mozilla::detail::log_test(gFocusLog,
LogLevel::Debug)), 0))) { nsAutoCString tag("(none)"_ns); if
(mFocusedElement.get()) { mFocusedElement.get()->NodeInfo
()->NameAtom()->ToUTF8String(tag); } do { const ::mozilla
::LogModule* moz_real_module = gFocusLog; if ((__builtin_expect
(!!(mozilla::detail::log_test(moz_real_module, LogLevel::Debug
)), 0))) { mozilla::detail::log_print(moz_real_module, LogLevel
::Debug, " Current Focus: %s", tag.get()); } } while (0); }
;
526
527 // use FLAG_BYMOVEFOCUS when switching focus with MoveFocus unless one of
528 // the other focus methods is already set, or we're just moving to the root
529 // or caret position.
530 if (aType != MOVEFOCUS_ROOT && aType != MOVEFOCUS_CARET &&
531 (aFlags & METHOD_MASK) == 0) {
532 aFlags |= FLAG_BYMOVEFOCUS;
533 }
534
535 nsCOMPtr<nsPIDOMWindowOuter> window;
536 if (aStartElement) {
537 window = GetCurrentWindow(aStartElement);
538 } else {
539 window = aWindow ? nsPIDOMWindowOuter::From(aWindow) : mFocusedWindow.get();
540 }
541
542 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(window)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "window" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 542); return NS_ERROR_FAILURE; } } while (false)
;
543
544 // Flush to ensure that focusability of descendants is computed correctly.
545 if (RefPtr<Document> doc = window->GetExtantDoc()) {
546 doc->FlushPendingNotifications(FlushType::EnsurePresShellInitAndFrames);
547 }
548
549 bool noParentTraversal = aFlags & FLAG_NOPARENTFRAME;
550 nsCOMPtr<nsIContent> newFocus;
551 nsresult rv = DetermineElementToMoveFocus(window, aStartElement, aType,
552 noParentTraversal, true,
553 getter_AddRefs(newFocus));
554 if (rv == NS_SUCCESS_DOM_NO_OPERATION) {
555 return NS_OK;
556 }
557
558 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 558); return rv; } } while (false)
;
559
560 LOGCONTENTNAVIGATION("Element to be focused: %s", newFocus.get())if ((__builtin_expect(!!(mozilla::detail::log_test(gFocusNavigationLog
, LogLevel::Debug)), 0))) { nsAutoCString tag("(none)"_ns); if
(newFocus.get()) { newFocus.get()->NodeInfo()->NameAtom
()->ToUTF8String(tag); } do { const ::mozilla::LogModule* moz_real_module
= gFocusNavigationLog; if ((__builtin_expect(!!(mozilla::detail
::log_test(moz_real_module, LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Debug, "Element to be focused: %s"
, tag.get()); } } while (0); }
;
561
562 if (newFocus && newFocus->IsElement()) {
563 // for caret movement, pass false for the aFocusChanged argument,
564 // otherwise the caret will end up moving to the focus position. This
565 // would be a problem because the caret would move to the beginning of the
566 // focused link making it impossible to navigate the caret over a link.
567 SetFocusInner(MOZ_KnownLive(newFocus->AsElement())(newFocus->AsElement()), aFlags,
568 aType != MOVEFOCUS_CARET, true);
569 *aElement = do_AddRef(newFocus->AsElement()).take();
570 } else if (aType == MOVEFOCUS_ROOT || aType == MOVEFOCUS_CARET) {
571 // no content was found, so clear the focus for these two types.
572 ClearFocus(window);
573 }
574
575 LOGFOCUS(("<<MoveFocus end>>"))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "<<MoveFocus end>>"
); } } while (0)
;
576
577 return NS_OK;
578}
579
580NS_IMETHODIMPnsresult
581nsFocusManager::ClearFocus(mozIDOMWindowProxy* aWindow) {
582 LOGFOCUS(("<<ClearFocus begin>>"))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "<<ClearFocus begin>>"
); } } while (0)
;
583
584 // if the window to clear is the focused window or an ancestor of the
585 // focused window, then blur the existing focused content. Otherwise, the
586 // focus is somewhere else so just update the current node.
587 NS_ENSURE_TRUE(aWindow, NS_ERROR_INVALID_ARG)do { if ((__builtin_expect(!!(!(aWindow)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aWindow" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 587); return NS_ERROR_INVALID_ARG; } } while (false)
;
588 nsCOMPtr<nsPIDOMWindowOuter> window = nsPIDOMWindowOuter::From(aWindow);
589
590 if (IsSameOrAncestor(window, GetFocusedBrowsingContext())) {
591 RefPtr<BrowsingContext> bc = window->GetBrowsingContext();
592 RefPtr<BrowsingContext> focusedBC = GetFocusedBrowsingContext();
593 const bool isAncestor = (focusedBC != bc);
594 RefPtr<BrowsingContext> ancestorBC = isAncestor ? bc : nullptr;
595 if (Blur(focusedBC, ancestorBC, isAncestor, true, false,
596 GenerateFocusActionId())) {
597 // if we are clearing the focus on an ancestor of the focused window,
598 // the ancestor will become the new focused window, so focus it
599 if (isAncestor) {
600 // Intentionally use a new actionId here because the above
601 // Blur() will clear the focus of the ancestors of focusedBC, and
602 // this Focus() call might need to update the focus of those ancestors,
603 // so it needs to have a newer actionId to make that happen.
604 Focus(window, nullptr, 0, true, false, false, true,
605 GenerateFocusActionId());
606 }
607 }
608 } else {
609 window->SetFocusedElement(nullptr);
610 }
611
612 LOGFOCUS(("<<ClearFocus end>>"))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "<<ClearFocus end>>"
); } } while (0)
;
613
614 return NS_OK;
615}
616
617NS_IMETHODIMPnsresult
618nsFocusManager::GetFocusedElementForWindow(mozIDOMWindowProxy* aWindow,
619 bool aDeep,
620 mozIDOMWindowProxy** aFocusedWindow,
621 Element** aElement) {
622 *aElement = nullptr;
623 if (aFocusedWindow) {
624 *aFocusedWindow = nullptr;
625 }
626
627 NS_ENSURE_TRUE(aWindow, NS_ERROR_INVALID_ARG)do { if ((__builtin_expect(!!(!(aWindow)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aWindow" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 627); return NS_ERROR_INVALID_ARG; } } while (false)
;
628 nsCOMPtr<nsPIDOMWindowOuter> window = nsPIDOMWindowOuter::From(aWindow);
629
630 nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
631 RefPtr<Element> focusedElement =
632 GetFocusedDescendant(window,
633 aDeep ? nsFocusManager::eIncludeAllDescendants
634 : nsFocusManager::eOnlyCurrentWindow,
635 getter_AddRefs(focusedWindow));
636
637 focusedElement.forget(aElement);
638
639 if (aFocusedWindow) {
640 NS_IF_ADDREF(*aFocusedWindow = focusedWindow)ns_if_addref(*aFocusedWindow = focusedWindow);
641 }
642
643 return NS_OK;
644}
645
646NS_IMETHODIMPnsresult
647nsFocusManager::MoveCaretToFocus(mozIDOMWindowProxy* aWindow) {
648 nsCOMPtr<nsIWebNavigation> webnav = do_GetInterface(aWindow);
649 nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(webnav);
650 if (dsti) {
651 if (dsti->ItemType() != nsIDocShellTreeItem::typeChrome) {
652 nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(dsti);
653 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(docShell)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "docShell" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 653); return NS_ERROR_FAILURE; } } while (false)
;
654
655 // don't move the caret for editable documents
656 bool isEditable;
657 docShell->GetEditable(&isEditable);
658 if (isEditable) {
659 return NS_OK;
660 }
661
662 RefPtr<PresShell> presShell = docShell->GetPresShell();
663 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(presShell)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "presShell" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 663); return NS_ERROR_FAILURE; } } while (false)
;
664
665 nsCOMPtr<nsPIDOMWindowOuter> window = nsPIDOMWindowOuter::From(aWindow);
666 if (RefPtr<Element> focusedElement = window->GetFocusedElement()) {
667 MoveCaretToFocus(presShell, focusedElement);
668 }
669 }
670 }
671
672 return NS_OK;
673}
674
675void nsFocusManager::WindowRaised(mozIDOMWindowProxy* aWindow,
676 uint64_t aActionId) {
677 if (!aWindow) {
678 return;
679 }
680
681 nsCOMPtr<nsPIDOMWindowOuter> window = nsPIDOMWindowOuter::From(aWindow);
682 BrowsingContext* bc = window->GetBrowsingContext();
683
684 if (MOZ_LOG_TEST(gFocusLog, LogLevel::Debug)(__builtin_expect(!!(mozilla::detail::log_test(gFocusLog, LogLevel
::Debug)), 0))
) {
685 LOGFOCUS(("Window %p Raised [Currently: %p %p] actionid: %" PRIu64, aWindow,do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Window %p Raised [Currently: %p %p] actionid: %"
"l" "u", aWindow, mActiveWindow.get(), mFocusedWindow.get(),
aActionId); } } while (0)
686 mActiveWindow.get(), mFocusedWindow.get(), aActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Window %p Raised [Currently: %p %p] actionid: %"
"l" "u", aWindow, mActiveWindow.get(), mFocusedWindow.get(),
aActionId); } } while (0)
;
687 Document* doc = window->GetExtantDoc();
688 if (doc && doc->GetDocumentURI()) {
689 LOGFOCUS((" Raised Window: %p %s", aWindow,do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Raised Window: %p %s"
, aWindow, doc->GetDocumentURI()->GetSpecOrDefault().get
()); } } while (0)
690 doc->GetDocumentURI()->GetSpecOrDefault().get()))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Raised Window: %p %s"
, aWindow, doc->GetDocumentURI()->GetSpecOrDefault().get
()); } } while (0)
;
691 }
692 if (mActiveWindow) {
693 doc = mActiveWindow->GetExtantDoc();
694 if (doc && doc->GetDocumentURI()) {
695 LOGFOCUS((" Active Window: %p %s", mActiveWindow.get(),do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Active Window: %p %s"
, mActiveWindow.get(), doc->GetDocumentURI()->GetSpecOrDefault
().get()); } } while (0)
696 doc->GetDocumentURI()->GetSpecOrDefault().get()))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Active Window: %p %s"
, mActiveWindow.get(), doc->GetDocumentURI()->GetSpecOrDefault
().get()); } } while (0)
;
697 }
698 }
699 }
700
701 if (XRE_IsParentProcess()) {
702 if (mActiveWindow == window) {
703 // The window is already active, so there is no need to focus anything,
704 // but make sure that the right widget is focused. This is a special case
705 // for Windows because when restoring a minimized window, a second
706 // activation will occur and the top-level widget could be focused instead
707 // of the child we want. We solve this by calling SetFocus to ensure that
708 // what the focus manager thinks should be the current widget is actually
709 // focused.
710 EnsureCurrentWidgetFocused(CallerType::System);
711 return;
712 }
713
714 // lower the existing window, if any. This shouldn't happen usually.
715 if (nsCOMPtr<nsPIDOMWindowOuter> activeWindow = mActiveWindow) {
716 WindowLowered(activeWindow, aActionId);
717 }
718 } else if (bc->IsTop()) {
719 BrowsingContext* active = GetActiveBrowsingContext();
720 if (active == bc && !mActiveBrowsingContextInContentSetFromOtherProcess) {
721 // EnsureCurrentWidgetFocused() should not be necessary with
722 // PuppetWidget.
723 return;
724 }
725
726 if (active && active != bc) {
727 if (active->IsInProcess()) {
728 nsCOMPtr<nsPIDOMWindowOuter> activeWindow = active->GetDOMWindow();
729 WindowLowered(activeWindow, aActionId);
730 }
731 // No else, because trying to lower other-process windows
732 // from here can result in the BrowsingContext no longer
733 // existing in the parent process by the time it deserializes
734 // the IPC message.
735 }
736 }
737
738 nsCOMPtr<nsIDocShellTreeItem> docShellAsItem = window->GetDocShell();
739 // If there's no docShellAsItem, this window must have been closed,
740 // in that case there is no tree owner.
741 if (!docShellAsItem) {
742 return;
743 }
744
745 // set this as the active window
746 if (XRE_IsParentProcess()) {
747 mActiveWindow = window;
748 } else if (bc->IsTop()) {
749 SetActiveBrowsingContextInContent(bc, aActionId,
750 false /* aIsEnteringBFCache */);
751 }
752
753 // ensure that the window is enabled and visible
754 nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
755 docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
756 nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(treeOwner);
757 if (baseWindow) {
758 bool isEnabled = true;
759 if (NS_SUCCEEDED(baseWindow->GetEnabled(&isEnabled))((bool)(__builtin_expect(!!(!NS_FAILED_impl(baseWindow->GetEnabled
(&isEnabled))), 1)))
&& !isEnabled) {
760 return;
761 }
762
763 baseWindow->SetVisibility(true);
764 }
765
766 if (XRE_IsParentProcess()) {
767 // Unsetting top-level focus upon lowering was inhibited to accommodate
768 // ATOK, so we need to do it here.
769 BrowserParent::UnsetTopLevelWebFocusAll();
770 ActivateOrDeactivate(window, true);
771 }
772
773 // retrieve the last focused element within the window that was raised
774 nsCOMPtr<nsPIDOMWindowOuter> currentWindow;
775 RefPtr<Element> currentFocus = GetFocusedDescendant(
776 window, eIncludeAllDescendants, getter_AddRefs(currentWindow));
777
778 NS_ASSERTION(currentWindow, "window raised with no window current")do { if (!(currentWindow)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "window raised with no window current", "currentWindow", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 778); MOZ_PretendNoReturn(); } } while (0)
;
779 if (!currentWindow) {
780 return;
781 }
782
783 nsCOMPtr<nsIAppWindow> appWin(do_GetInterface(baseWindow));
784 // We use mFocusedWindow here is basically for the case that iframe navigate
785 // from a.com to b.com for example, so it ends up being loaded in a different
786 // process after Fission, but
787 // currentWindow->GetBrowsingContext() == GetFocusedBrowsingContext() would
788 // still be true because focused browsing context is synced, and we won't
789 // fire a focus event while focusing if we use it as condition.
790 Focus(currentWindow, currentFocus, 0, currentWindow != mFocusedWindow, false,
791 appWin != nullptr, true, aActionId);
792}
793
794void nsFocusManager::WindowLowered(mozIDOMWindowProxy* aWindow,
795 uint64_t aActionId) {
796 if (!aWindow) {
797 return;
798 }
799
800 nsCOMPtr<nsPIDOMWindowOuter> window = nsPIDOMWindowOuter::From(aWindow);
801
802 if (MOZ_LOG_TEST(gFocusLog, LogLevel::Debug)(__builtin_expect(!!(mozilla::detail::log_test(gFocusLog, LogLevel
::Debug)), 0))
) {
803 LOGFOCUS(("Window %p Lowered [Currently: %p %p]", aWindow,do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Window %p Lowered [Currently: %p %p]"
, aWindow, mActiveWindow.get(), mFocusedWindow.get()); } } while
(0)
804 mActiveWindow.get(), mFocusedWindow.get()))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Window %p Lowered [Currently: %p %p]"
, aWindow, mActiveWindow.get(), mFocusedWindow.get()); } } while
(0)
;
805 Document* doc = window->GetExtantDoc();
806 if (doc && doc->GetDocumentURI()) {
807 LOGFOCUS((" Lowered Window: %s",do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Lowered Window: %s"
, doc->GetDocumentURI()->GetSpecOrDefault().get()); } }
while (0)
808 doc->GetDocumentURI()->GetSpecOrDefault().get()))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Lowered Window: %s"
, doc->GetDocumentURI()->GetSpecOrDefault().get()); } }
while (0)
;
809 }
810 if (mActiveWindow) {
811 doc = mActiveWindow->GetExtantDoc();
812 if (doc && doc->GetDocumentURI()) {
813 LOGFOCUS((" Active Window: %s",do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Active Window: %s"
, doc->GetDocumentURI()->GetSpecOrDefault().get()); } }
while (0)
814 doc->GetDocumentURI()->GetSpecOrDefault().get()))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Active Window: %s"
, doc->GetDocumentURI()->GetSpecOrDefault().get()); } }
while (0)
;
815 }
816 }
817 }
818
819 if (XRE_IsParentProcess()) {
820 if (mActiveWindow != window) {
821 return;
822 }
823 } else {
824 BrowsingContext* bc = window->GetBrowsingContext();
825 BrowsingContext* active = GetActiveBrowsingContext();
826 if (active != bc->Top()) {
827 return;
828 }
829 }
830
831 // clear the mouse capture as the active window has changed
832 PresShell::ReleaseCapturingContent();
833
834 // In addition, reset the drag state to ensure that we are no longer in
835 // drag-select mode.
836 if (mFocusedWindow) {
837 nsCOMPtr<nsIDocShell> docShell = mFocusedWindow->GetDocShell();
838 if (docShell) {
839 if (PresShell* presShell = docShell->GetPresShell()) {
840 RefPtr<nsFrameSelection> frameSelection = presShell->FrameSelection();
841 frameSelection->SetDragState(false);
842 }
843 }
844 }
845
846 if (XRE_IsParentProcess()) {
847 ActivateOrDeactivate(window, false);
848 }
849
850 // keep track of the window being lowered, so that attempts to raise the
851 // window can be prevented until we return. Otherwise, focus can get into
852 // an unusual state.
853 mWindowBeingLowered = window;
854 if (XRE_IsParentProcess()) {
855 mActiveWindow = nullptr;
856 } else {
857 BrowsingContext* bc = window->GetBrowsingContext();
858 if (bc == bc->Top()) {
859 SetActiveBrowsingContextInContent(nullptr, aActionId,
860 false /* aIsEnteringBFCache */);
861 }
862 }
863
864 if (mFocusedWindow) {
865 Blur(nullptr, nullptr, true, true, false, aActionId);
866 }
867
868 mWindowBeingLowered = nullptr;
869}
870
871nsresult nsFocusManager::ContentRemoved(Document* aDocument,
872 nsIContent* aContent) {
873 NS_ENSURE_ARG(aDocument)do { if ((__builtin_expect(!!(!(aDocument)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aDocument" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 873); return NS_ERROR_INVALID_ARG; } } while (false)
;
874 NS_ENSURE_ARG(aContent)do { if ((__builtin_expect(!!(!(aContent)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aContent" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 874); return NS_ERROR_INVALID_ARG; } } while (false)
;
875
876 nsPIDOMWindowOuter* windowPtr = aDocument->GetWindow();
877 if (!windowPtr) {
878 return NS_OK;
879 }
880
881 // if the content is currently focused in the window, or is an
882 // shadow-including inclusive ancestor of the currently focused element,
883 // reset the focus within that window.
884 Element* previousFocusedElementPtr = windowPtr->GetFocusedElement();
885 if (!previousFocusedElementPtr) {
886 return NS_OK;
887 }
888
889 if (!nsContentUtils::ContentIsHostIncludingDescendantOf(
890 previousFocusedElementPtr, aContent)) {
891 return NS_OK;
892 }
893
894 RefPtr<nsPIDOMWindowOuter> window = windowPtr;
895 RefPtr<Element> previousFocusedElement = previousFocusedElementPtr;
896
897 RefPtr<Element> newFocusedElement = [&]() -> Element* {
898 if (auto* sr = ShadowRoot::FromNode(aContent)) {
899 if (sr->IsUAWidget() && sr->Host()->IsHTMLElement(nsGkAtoms::input)) {
900 return sr->Host();
901 }
902 }
903 return nullptr;
904 }();
905
906 window->SetFocusedElement(newFocusedElement);
907
908 // if this window is currently focused, clear the global focused
909 // element as well, but don't fire any events.
910 if (window->GetBrowsingContext() == GetFocusedBrowsingContext()) {
911 mFocusedElement = newFocusedElement;
912 } else if (Document* subdoc =
913 aDocument->GetSubDocumentFor(previousFocusedElement)) {
914 // Check if the node that was focused is an iframe or similar by looking if
915 // it has a subdocument. This would indicate that this focused iframe
916 // and its descendants will be going away. We will need to move the focus
917 // somewhere else, so just clear the focus in the toplevel window so that no
918 // element is focused.
919 //
920 // The Fission case is handled in FlushAndCheckIfFocusable().
921 if (nsCOMPtr<nsIDocShell> docShell = subdoc->GetDocShell()) {
922 nsCOMPtr<nsPIDOMWindowOuter> childWindow = docShell->GetWindow();
923 if (childWindow &&
924 IsSameOrAncestor(childWindow, GetFocusedBrowsingContext())) {
925 if (XRE_IsParentProcess()) {
926 nsCOMPtr<nsPIDOMWindowOuter> activeWindow = mActiveWindow;
927 ClearFocus(activeWindow);
928 } else {
929 BrowsingContext* active = GetActiveBrowsingContext();
930 if (active) {
931 if (active->IsInProcess()) {
932 nsCOMPtr<nsPIDOMWindowOuter> activeWindow =
933 active->GetDOMWindow();
934 ClearFocus(activeWindow);
935 } else {
936 mozilla::dom::ContentChild* contentChild =
937 mozilla::dom::ContentChild::GetSingleton();
938 MOZ_ASSERT(contentChild)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(contentChild)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(contentChild))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("contentChild", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 938); AnnotateMozCrashReason("MOZ_ASSERT" "(" "contentChild"
")"); do { *((volatile int*)__null) = 938; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
939 contentChild->SendClearFocus(active);
940 }
941 } // no else, because ClearFocus does nothing with nullptr
942 }
943 }
944 }
945 }
946
947 // Notify the editor in case we removed its ancestor limiter.
948 if (previousFocusedElement->IsEditable()) {
949 if (nsIDocShell* const docShell = aDocument->GetDocShell()) {
950 if (HTMLEditor* const htmlEditor = docShell->GetHTMLEditor()) {
951 Selection* const selection = htmlEditor->GetSelection();
952 if (selection && selection->GetFrameSelection() &&
953 previousFocusedElement ==
954 selection->GetFrameSelection()->GetAncestorLimiter()) {
955 // The editing host may be being removed right now. So, it's already
956 // removed from the child chain of the parent node, but it still know
957 // the parent node. This could cause unexpected result at scheduling
958 // paint of the caret. Therefore, we should call FinalizeSelection
959 // after unblocking to run the script.
960 nsContentUtils::AddScriptRunner(
961 NewRunnableMethod("HTMLEditor::FinalizeSelection", htmlEditor,
962 &HTMLEditor::FinalizeSelection));
963 }
964 }
965 }
966 }
967
968 if (!newFocusedElement) {
969 NotifyFocusStateChange(previousFocusedElement, newFocusedElement, 0,
970 /* aGettingFocus = */ false, false);
971 } else {
972 // We should already have the right state, which is managed by the <input>
973 // widget.
974 MOZ_ASSERT(newFocusedElement->State().HasState(ElementState::FOCUS))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(newFocusedElement->State().HasState(ElementState::
FOCUS))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(newFocusedElement->State().HasState(ElementState::
FOCUS)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("newFocusedElement->State().HasState(ElementState::FOCUS)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 974); AnnotateMozCrashReason("MOZ_ASSERT" "(" "newFocusedElement->State().HasState(ElementState::FOCUS)"
")"); do { *((volatile int*)__null) = 974; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
975 }
976
977 // If we changed focused element and the element still has focus, let's
978 // notify IME of focus. Note that if new focus move has already occurred
979 // by running script, we should not let IMEStateManager of outdated focus
980 // change.
981 if (mFocusedElement == newFocusedElement && mFocusedWindow == window) {
982 RefPtr<nsPresContext> presContext(aDocument->GetPresContext());
983 IMEStateManager::OnChangeFocus(presContext, newFocusedElement,
984 InputContextAction::Cause::CAUSE_UNKNOWN);
985 }
986
987 return NS_OK;
988}
989
990void nsFocusManager::WindowShown(mozIDOMWindowProxy* aWindow,
991 bool aNeedsFocus) {
992 if (!aWindow) {
993 return;
994 }
995
996 nsCOMPtr<nsPIDOMWindowOuter> window = nsPIDOMWindowOuter::From(aWindow);
997
998 if (MOZ_LOG_TEST(gFocusLog, LogLevel::Debug)(__builtin_expect(!!(mozilla::detail::log_test(gFocusLog, LogLevel
::Debug)), 0))
) {
999 LOGFOCUS(("Window %p Shown [Currently: %p %p]", window.get(),do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Window %p Shown [Currently: %p %p]"
, window.get(), mActiveWindow.get(), mFocusedWindow.get()); }
} while (0)
1000 mActiveWindow.get(), mFocusedWindow.get()))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Window %p Shown [Currently: %p %p]"
, window.get(), mActiveWindow.get(), mFocusedWindow.get()); }
} while (0)
;
1001 Document* doc = window->GetExtantDoc();
1002 if (doc && doc->GetDocumentURI()) {
1003 LOGFOCUS(("Shown Window: %s",do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Shown Window: %s"
, doc->GetDocumentURI()->GetSpecOrDefault().get()); } }
while (0)
1004 doc->GetDocumentURI()->GetSpecOrDefault().get()))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Shown Window: %s"
, doc->GetDocumentURI()->GetSpecOrDefault().get()); } }
while (0)
;
1005 }
1006
1007 if (mFocusedWindow) {
1008 doc = mFocusedWindow->GetExtantDoc();
1009 if (doc && doc->GetDocumentURI()) {
1010 LOGFOCUS((" Focused Window: %s",do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Focused Window: %s"
, doc->GetDocumentURI()->GetSpecOrDefault().get()); } }
while (0)
1011 doc->GetDocumentURI()->GetSpecOrDefault().get()))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Focused Window: %s"
, doc->GetDocumentURI()->GetSpecOrDefault().get()); } }
while (0)
;
1012 }
1013 }
1014 }
1015
1016 if (XRE_IsParentProcess()) {
1017 if (BrowsingContext* bc = window->GetBrowsingContext()) {
1018 if (bc->IsTop()) {
1019 bc->SetIsActiveBrowserWindow(bc->GetIsActiveBrowserWindow());
1020 }
1021 }
1022 }
1023
1024 if (XRE_IsParentProcess()) {
1025 if (mFocusedWindow != window) {
1026 return;
1027 }
1028 } else {
1029 BrowsingContext* bc = window->GetBrowsingContext();
1030 if (!bc || mFocusedBrowsingContextInContent != bc) {
1031 return;
1032 }
1033 // Sync the window for a newly-created OOP iframe
1034 // Set actionId to zero to signify that it should be ignored.
1035 SetFocusedWindowInternal(window, 0, false);
1036 }
1037
1038 if (aNeedsFocus) {
1039 nsCOMPtr<nsPIDOMWindowOuter> currentWindow;
1040 RefPtr<Element> currentFocus = GetFocusedDescendant(
1041 window, eIncludeAllDescendants, getter_AddRefs(currentWindow));
1042
1043 if (currentWindow) {
1044 Focus(currentWindow, currentFocus, 0, true, false, false, true,
1045 GenerateFocusActionId());
1046 }
1047 } else {
1048 // Sometimes, an element in a window can be focused before the window is
1049 // visible, which would mean that the widget may not be properly focused.
1050 // When the window becomes visible, make sure the right widget is focused.
1051 EnsureCurrentWidgetFocused(CallerType::System);
1052 }
1053}
1054
1055void nsFocusManager::WindowHidden(mozIDOMWindowProxy* aWindow,
1056 uint64_t aActionId, bool aIsEnteringBFCache) {
1057 // if there is no window or it is not the same or an ancestor of the
1058 // currently focused window, just return, as the current focus will not
1059 // be affected.
1060
1061 if (!aWindow) {
1062 return;
1063 }
1064
1065 nsCOMPtr<nsPIDOMWindowOuter> window = nsPIDOMWindowOuter::From(aWindow);
1066
1067 if (MOZ_LOG_TEST(gFocusLog, LogLevel::Debug)(__builtin_expect(!!(mozilla::detail::log_test(gFocusLog, LogLevel
::Debug)), 0))
) {
1068 LOGFOCUS(("Window %p Hidden [Currently: %p %p] actionid: %" PRIu64,do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Window %p Hidden [Currently: %p %p] actionid: %"
"l" "u", window.get(), mActiveWindow.get(), mFocusedWindow.get
(), aActionId); } } while (0)
1069 window.get(), mActiveWindow.get(), mFocusedWindow.get(),do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Window %p Hidden [Currently: %p %p] actionid: %"
"l" "u", window.get(), mActiveWindow.get(), mFocusedWindow.get
(), aActionId); } } while (0)
1070 aActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Window %p Hidden [Currently: %p %p] actionid: %"
"l" "u", window.get(), mActiveWindow.get(), mFocusedWindow.get
(), aActionId); } } while (0)
;
1071 nsAutoCString spec;
1072 Document* doc = window->GetExtantDoc();
1073 if (doc && doc->GetDocumentURI()) {
1074 LOGFOCUS((" Hide Window: %s",do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Hide Window: %s"
, doc->GetDocumentURI()->GetSpecOrDefault().get()); } }
while (0)
1075 doc->GetDocumentURI()->GetSpecOrDefault().get()))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Hide Window: %s"
, doc->GetDocumentURI()->GetSpecOrDefault().get()); } }
while (0)
;
1076 }
1077
1078 if (mFocusedWindow) {
1079 doc = mFocusedWindow->GetExtantDoc();
1080 if (doc && doc->GetDocumentURI()) {
1081 LOGFOCUS((" Focused Window: %s",do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Focused Window: %s"
, doc->GetDocumentURI()->GetSpecOrDefault().get()); } }
while (0)
1082 doc->GetDocumentURI()->GetSpecOrDefault().get()))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Focused Window: %s"
, doc->GetDocumentURI()->GetSpecOrDefault().get()); } }
while (0)
;
1083 }
1084 }
1085
1086 if (mActiveWindow) {
1087 doc = mActiveWindow->GetExtantDoc();
1088 if (doc && doc->GetDocumentURI()) {
1089 LOGFOCUS((" Active Window: %s",do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Active Window: %s"
, doc->GetDocumentURI()->GetSpecOrDefault().get()); } }
while (0)
1090 doc->GetDocumentURI()->GetSpecOrDefault().get()))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Active Window: %s"
, doc->GetDocumentURI()->GetSpecOrDefault().get()); } }
while (0)
;
1091 }
1092 }
1093 }
1094
1095 if (!IsSameOrAncestor(window, mFocusedWindow)) {
1096 return;
1097 }
1098
1099 // at this point, we know that the window being hidden is either the focused
1100 // window, or an ancestor of the focused window. Either way, the focus is no
1101 // longer valid, so it needs to be updated.
1102
1103 const RefPtr<Element> oldFocusedElement = std::move(mFocusedElement);
1104
1105 nsCOMPtr<nsIDocShell> focusedDocShell = mFocusedWindow->GetDocShell();
1106 if (!focusedDocShell) {
1107 return;
1108 }
1109
1110 const RefPtr<PresShell> presShell = focusedDocShell->GetPresShell();
1111
1112 if (oldFocusedElement && oldFocusedElement->IsInComposedDoc()) {
1113 NotifyFocusStateChange(oldFocusedElement, nullptr, 0, false, false);
1114 window->UpdateCommands(u"focus"_ns);
1115
1116 if (presShell) {
1117 RefPtr<Document> composedDoc = oldFocusedElement->GetComposedDoc();
1118 SendFocusOrBlurEvent(eBlur, presShell, composedDoc, oldFocusedElement,
1119 false);
1120 }
1121 }
1122
1123 const RefPtr<nsPresContext> focusedPresContext =
1124 presShell ? presShell->GetPresContext() : nullptr;
1125 IMEStateManager::OnChangeFocus(focusedPresContext, nullptr,
1126 GetFocusMoveActionCause(0));
1127 if (presShell) {
1128 SetCaretVisible(presShell, false, nullptr);
1129 }
1130
1131 // If a window is being "hidden" because its BrowsingContext is changing
1132 // remoteness, we don't want to handle docshell destruction by moving focus.
1133 // Instead, the focused browsing context should stay the way it is (so that
1134 // the newly "shown" window in the other process knows to take focus) and
1135 // we should just null out the process-local field.
1136 nsCOMPtr<nsIDocShell> docShellBeingHidden = window->GetDocShell();
1137 // Check if we're currently hiding a non-remote nsDocShell due to its
1138 // BrowsingContext navigating to become remote. Normally, when a focused
1139 // subframe is hidden, focus is moved to the frame element, but focus should
1140 // stay with the BrowsingContext when performing a process switch. We don't
1141 // need to consider process switches where the hiding docshell is already
1142 // remote (ie. GetEmbedderElement is nullptr), as shifting remoteness to the
1143 // frame element is handled elsewhere.
1144 if (docShellBeingHidden &&
1145 nsDocShell::Cast(docShellBeingHidden)->WillChangeProcess() &&
1146 docShellBeingHidden->GetBrowsingContext()->GetEmbedderElement()) {
1147 if (mFocusedWindow != window) {
1148 // The window being hidden is an ancestor of the focused window.
1149#ifdef DEBUG1
1150 BrowsingContext* ancestor = window->GetBrowsingContext();
1151 BrowsingContext* bc = mFocusedWindow->GetBrowsingContext();
1152 for (;;) {
1153 if (!bc) {
1154 MOZ_ASSERT(false, "Should have found ancestor")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "Should have found ancestor"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1154); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"Should have found ancestor" ")"); do { *((volatile int*)__null
) = 1154; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
1155 }
1156 bc = bc->GetParent();
1157 if (ancestor == bc) {
1158 break;
1159 }
1160 }
1161#endif
1162 // This call adjusts the focused browsing context and window.
1163 // The latter gets nulled out immediately below.
1164 SetFocusedWindowInternal(window, aActionId);
1165 }
1166 mFocusedWindow = nullptr;
1167 window->SetFocusedElement(nullptr);
1168 return;
1169 }
1170
1171 // if the docshell being hidden is being destroyed, then we want to move
1172 // focus somewhere else. Call ClearFocus on the toplevel window, which
1173 // will have the effect of clearing the focus and moving the focused window
1174 // to the toplevel window. But if the window isn't being destroyed, we are
1175 // likely just loading a new document in it, so we want to maintain the
1176 // focused window so that the new document gets properly focused.
1177 bool beingDestroyed = !docShellBeingHidden;
1178 if (docShellBeingHidden) {
1179 docShellBeingHidden->IsBeingDestroyed(&beingDestroyed);
1180 }
1181 if (beingDestroyed) {
1182 // There is usually no need to do anything if a toplevel window is going
1183 // away, as we assume that WindowLowered will be called. However, this may
1184 // not happen if nsIAppStartup::eForceQuit is used to quit, and can cause
1185 // a leak. So if the active window is being destroyed, call WindowLowered
1186 // directly.
1187
1188 if (XRE_IsParentProcess()) {
1189 nsCOMPtr<nsPIDOMWindowOuter> activeWindow = mActiveWindow;
1190 if (activeWindow == mFocusedWindow || activeWindow == window) {
1191 WindowLowered(activeWindow, aActionId);
1192 } else {
1193 ClearFocus(activeWindow);
1194 }
1195 } else {
1196 BrowsingContext* active = GetActiveBrowsingContext();
1197 if (active) {
1198 if (nsCOMPtr<nsPIDOMWindowOuter> activeWindow =
1199 active->GetDOMWindow()) {
1200 if ((mFocusedWindow &&
1201 mFocusedWindow->GetBrowsingContext() == active) ||
1202 (window->GetBrowsingContext() == active)) {
1203 WindowLowered(activeWindow, aActionId);
1204 } else {
1205 ClearFocus(activeWindow);
1206 }
1207 } // else do nothing when an out-of-process iframe is torn down
1208 }
1209 }
1210 return;
1211 }
1212
1213 if (!XRE_IsParentProcess() &&
1214 mActiveBrowsingContextInContent ==
1215 docShellBeingHidden->GetBrowsingContext() &&
1216 mActiveBrowsingContextInContent->GetIsInBFCache()) {
1217 SetActiveBrowsingContextInContent(nullptr, aActionId, aIsEnteringBFCache);
1218 }
1219
1220 // if the window being hidden is an ancestor of the focused window, adjust
1221 // the focused window so that it points to the one being hidden. This
1222 // ensures that the focused window isn't in a chain of frames that doesn't
1223 // exist any more.
1224 if (window != mFocusedWindow) {
1225 nsCOMPtr<nsIDocShellTreeItem> dsti =
1226 mFocusedWindow ? mFocusedWindow->GetDocShell() : nullptr;
1227 if (dsti) {
1228 nsCOMPtr<nsIDocShellTreeItem> parentDsti;
1229 dsti->GetInProcessParent(getter_AddRefs(parentDsti));
1230 if (parentDsti) {
1231 if (nsCOMPtr<nsPIDOMWindowOuter> parentWindow =
1232 parentDsti->GetWindow()) {
1233 parentWindow->SetFocusedElement(nullptr);
1234 }
1235 }
1236 }
1237
1238 SetFocusedWindowInternal(window, aActionId);
1239 }
1240}
1241
1242void nsFocusManager::FireDelayedEvents(Document* aDocument) {
1243 MOZ_ASSERT(aDocument)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aDocument)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aDocument))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aDocument", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1243); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDocument" ")"
); do { *((volatile int*)__null) = 1243; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1244
1245 // fire any delayed focus and blur events in the same order that they were
1246 // added
1247 for (uint32_t i = 0; i < mDelayedBlurFocusEvents.Length(); i++) {
1248 if (mDelayedBlurFocusEvents[i].mDocument == aDocument) {
1249 if (!aDocument->GetInnerWindow() ||
1250 !aDocument->GetInnerWindow()->IsCurrentInnerWindow()) {
1251 // If the document was navigated away from or is defunct, don't bother
1252 // firing events on it. Note the symmetry between this condition and
1253 // the similar one in Document.cpp:FireOrClearDelayedEvents.
1254 mDelayedBlurFocusEvents.RemoveElementAt(i);
1255 --i;
1256 } else if (!aDocument->EventHandlingSuppressed()) {
1257 EventMessage message = mDelayedBlurFocusEvents[i].mEventMessage;
1258 nsCOMPtr<EventTarget> target = mDelayedBlurFocusEvents[i].mTarget;
1259 RefPtr<PresShell> presShell = mDelayedBlurFocusEvents[i].mPresShell;
1260 nsCOMPtr<EventTarget> relatedTarget =
1261 mDelayedBlurFocusEvents[i].mRelatedTarget;
1262 mDelayedBlurFocusEvents.RemoveElementAt(i);
1263
1264 FireFocusOrBlurEvent(message, presShell, target, false, false,
1265 relatedTarget);
1266 --i;
1267 }
1268 }
1269 }
1270}
1271
1272void nsFocusManager::WasNuked(nsPIDOMWindowOuter* aWindow) {
1273 MOZ_ASSERT(aWindow, "Expected non-null window.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aWindow)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aWindow))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aWindow" " (" "Expected non-null window."
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1273); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWindow" ") ("
"Expected non-null window." ")"); do { *((volatile int*)__null
) = 1273; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
1274 MOZ_ASSERT(aWindow != mActiveWindow,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aWindow != mActiveWindow)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aWindow != mActiveWindow))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aWindow != mActiveWindow"
" (" "How come we're nuking a window that's still active?" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1275); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWindow != mActiveWindow"
") (" "How come we're nuking a window that's still active?" ")"
); do { *((volatile int*)__null) = 1275; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1275 "How come we're nuking a window that's still active?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aWindow != mActiveWindow)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aWindow != mActiveWindow))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aWindow != mActiveWindow"
" (" "How come we're nuking a window that's still active?" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1275); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aWindow != mActiveWindow"
") (" "How come we're nuking a window that's still active?" ")"
); do { *((volatile int*)__null) = 1275; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1276 if (aWindow == mFocusedWindow) {
1277 mFocusedWindow = nullptr;
1278 SetFocusedBrowsingContext(nullptr, GenerateFocusActionId());
1279 mFocusedElement = nullptr;
1280 }
1281}
1282
1283nsFocusManager::BlurredElementInfo::BlurredElementInfo(Element& aElement)
1284 : mElement(aElement) {}
1285
1286nsFocusManager::BlurredElementInfo::~BlurredElementInfo() = default;
1287
1288// https://drafts.csswg.org/selectors-4/#the-focus-visible-pseudo
1289static bool ShouldMatchFocusVisible(nsPIDOMWindowOuter* aWindow,
1290 const Element& aElement,
1291 int32_t aFocusFlags) {
1292 // If we were explicitly requested to show the ring, do it.
1293 if (aFocusFlags & nsIFocusManager::FLAG_SHOWRING) {
1294 return true;
1295 }
1296
1297 if (aFocusFlags & nsIFocusManager::FLAG_NOSHOWRING) {
1298 return false;
1299 }
1300
1301 if (aWindow->ShouldShowFocusRing()) {
1302 // The window decision also trumps any other heuristic.
1303 return true;
1304 }
1305
1306 // Any element which supports keyboard input (such as an input element, or any
1307 // other element which may trigger a virtual keyboard to be shown on focus if
1308 // a physical keyboard is not present) should always match :focus-visible when
1309 // focused.
1310 {
1311 if (aElement.IsHTMLElement(nsGkAtoms::textarea) || aElement.IsEditable()) {
1312 return true;
1313 }
1314
1315 if (auto* input = HTMLInputElement::FromNode(aElement)) {
1316 if (input->IsSingleLineTextControl()) {
1317 return true;
1318 }
1319 }
1320 }
1321
1322 switch (nsFocusManager::GetFocusMoveActionCause(aFocusFlags)) {
1323 case InputContextAction::CAUSE_KEY:
1324 // If the user interacts with the page via the keyboard, the currently
1325 // focused element should match :focus-visible (i.e. keyboard usage may
1326 // change whether this pseudo-class matches even if it doesn't affect
1327 // :focus).
1328 return true;
1329 case InputContextAction::CAUSE_UNKNOWN:
1330 // We render outlines if the last "known" focus method was by key or there
1331 // was no previous known focus method, otherwise we don't.
1332 return aWindow->UnknownFocusMethodShouldShowOutline();
1333 case InputContextAction::CAUSE_MOUSE:
1334 case InputContextAction::CAUSE_TOUCH:
1335 case InputContextAction::CAUSE_LONGPRESS:
1336 // If the user interacts with the page via a pointing device, such that
1337 // the focus is moved to a new element which does not support user input,
1338 // the newly focused element should not match :focus-visible.
1339 return false;
1340 case InputContextAction::CAUSE_UNKNOWN_CHROME:
1341 case InputContextAction::CAUSE_UNKNOWN_DURING_KEYBOARD_INPUT:
1342 case InputContextAction::CAUSE_UNKNOWN_DURING_NON_KEYBOARD_INPUT:
1343 // TODO(emilio): We could return some of these though, looking at
1344 // UserActivation. We may want to suppress focus rings for unknown /
1345 // programatic focus if the user is interacting with the page but not
1346 // during keyboard input, or such.
1347 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: "
"These don't get returned by GetFocusMoveActionCause" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1348); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "These don't get returned by GetFocusMoveActionCause"
")"); do { *((volatile int*)__null) = 1348; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1348 "These don't get returned by GetFocusMoveActionCause")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: "
"These don't get returned by GetFocusMoveActionCause" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1348); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "These don't get returned by GetFocusMoveActionCause"
")"); do { *((volatile int*)__null) = 1348; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1349 break;
1350 }
1351 return false;
1352}
1353
1354/* static */
1355void nsFocusManager::NotifyFocusStateChange(Element* aElement,
1356 Element* aElementToFocus,
1357 int32_t aFlags, bool aGettingFocus,
1358 bool aShouldShowFocusRing) {
1359 MOZ_ASSERT_IF(aElementToFocus, !aGettingFocus)do { if (aElementToFocus) { do { static_assert( mozilla::detail
::AssertionConditionType<decltype(!aGettingFocus)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aGettingFocus))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aGettingFocus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1359); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aGettingFocus"
")"); do { *((volatile int*)__null) = 1359; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
1360 nsIContent* commonAncestor = nullptr;
1361 if (aElementToFocus) {
1362 commonAncestor = nsContentUtils::GetCommonFlattenedTreeAncestor(
1363 aElement, aElementToFocus);
1364 }
1365
1366 if (aGettingFocus) {
1367 ElementState stateToAdd = ElementState::FOCUS;
1368 if (aShouldShowFocusRing) {
1369 stateToAdd |= ElementState::FOCUSRING;
1370 }
1371 aElement->AddStates(stateToAdd);
1372
1373 for (nsIContent* host = aElement->GetContainingShadowHost(); host;
1374 host = host->GetContainingShadowHost()) {
1375 host->AsElement()->AddStates(ElementState::FOCUS);
1376 }
1377 } else {
1378 constexpr auto kStatesToRemove =
1379 ElementState::FOCUS | ElementState::FOCUSRING;
1380 aElement->RemoveStates(kStatesToRemove);
1381 for (nsIContent* host = aElement->GetContainingShadowHost(); host;
1382 host = host->GetContainingShadowHost()) {
1383 host->AsElement()->RemoveStates(kStatesToRemove);
1384 }
1385 }
1386
1387 // Special case for <input type="checkbox"> and <input type="radio">.
1388 // The other browsers cancel active state when they gets lost focus, but
1389 // does not do it for the other elements such as <button> and <a href="...">.
1390 // Additionally, they may be activated with <label>, but they will get focus
1391 // at `click`, but activated at `mousedown`. Therefore, we need to cancel
1392 // active state at moving focus.
1393 if (RefPtr<nsPresContext> presContext =
1394 aElement->GetPresContext(Element::PresContextFor::eForComposedDoc)) {
1395 RefPtr<EventStateManager> esm = presContext->EventStateManager();
1396 auto* activeInputElement =
1397 HTMLInputElement::FromNodeOrNull(esm->GetActiveContent());
1398 if (activeInputElement &&
1399 (activeInputElement->ControlType() == FormControlType::InputCheckbox ||
1400 activeInputElement->ControlType() == FormControlType::InputRadio) &&
1401 !activeInputElement->State().HasState(ElementState::FOCUS)) {
1402 esm->SetContentState(nullptr, ElementState::ACTIVE);
1403 }
1404 }
1405
1406 for (nsIContent* content = aElement; content && content != commonAncestor;
1407 content = content->GetFlattenedTreeParent()) {
1408 Element* element = Element::FromNode(content);
1409 if (!element) {
1410 continue;
1411 }
1412
1413 if (aGettingFocus) {
1414 if (element->State().HasState(ElementState::FOCUS_WITHIN)) {
1415 break;
1416 }
1417 element->AddStates(ElementState::FOCUS_WITHIN);
1418 } else {
1419 element->RemoveStates(ElementState::FOCUS_WITHIN);
1420 }
1421 }
1422}
1423
1424// static
1425void nsFocusManager::EnsureCurrentWidgetFocused(CallerType aCallerType) {
1426 if (!mFocusedWindow || sTestMode) return;
1427
1428 // get the main child widget for the focused window and ensure that the
1429 // platform knows that this widget is focused.
1430 nsCOMPtr<nsIDocShell> docShell = mFocusedWindow->GetDocShell();
1431 if (!docShell) {
1432 return;
1433 }
1434 RefPtr<PresShell> presShell = docShell->GetPresShell();
1435 if (!presShell) {
1436 return;
1437 }
1438 nsViewManager* vm = presShell->GetViewManager();
1439 if (!vm) {
1440 return;
1441 }
1442 nsCOMPtr<nsIWidget> widget = vm->GetRootWidget();
1443 if (!widget) {
1444 return;
1445 }
1446 widget->SetFocus(nsIWidget::Raise::No, aCallerType);
1447}
1448
1449void nsFocusManager::ActivateOrDeactivate(nsPIDOMWindowOuter* aWindow,
1450 bool aActive) {
1451 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1451); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 1451; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1452 if (!aWindow) {
1453 return;
1454 }
1455
1456 if (BrowsingContext* bc = aWindow->GetBrowsingContext()) {
1457 MOZ_ASSERT(bc->IsTop())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(bc->IsTop())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bc->IsTop()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("bc->IsTop()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1457); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bc->IsTop()"
")"); do { *((volatile int*)__null) = 1457; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1458
1459 RefPtr<CanonicalBrowsingContext> chromeTop =
1460 bc->Canonical()->TopCrossChromeBoundary();
1461 MOZ_ASSERT(bc == chromeTop)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(bc == chromeTop)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bc == chromeTop))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("bc == chromeTop"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1461); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bc == chromeTop"
")"); do { *((volatile int*)__null) = 1461; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1462
1463 chromeTop->SetIsActiveBrowserWindow(aActive);
1464 chromeTop->CallOnAllTopDescendants(
1465 [aActive](CanonicalBrowsingContext* aBrowsingContext) {
1466 aBrowsingContext->SetIsActiveBrowserWindow(aActive);
1467 return CallState::Continue;
1468 },
1469 /* aIncludeNestedBrowsers = */ true);
1470 }
1471
1472 if (aWindow->GetExtantDoc()) {
1473 nsContentUtils::DispatchEventOnlyToChrome(
1474 aWindow->GetExtantDoc(),
1475 nsGlobalWindowInner::Cast(aWindow->GetCurrentInnerWindow()),
1476 aActive ? u"activate"_ns : u"deactivate"_ns, CanBubble::eYes,
1477 Cancelable::eYes, nullptr);
1478 }
1479}
1480
1481// Retrieves innerWindowId of the window of the last focused element to
1482// log a warning to the website console.
1483void LogWarningFullscreenWindowRaise(Element* aElement) {
1484 nsCOMPtr<nsFrameLoaderOwner> frameLoaderOwner(do_QueryInterface(aElement));
1485 NS_ENSURE_TRUE_VOID(frameLoaderOwner)do { if ((__builtin_expect(!!(!(frameLoaderOwner)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "frameLoaderOwner" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1485); return; } } while (false)
;
1486
1487 RefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
1488 NS_ENSURE_TRUE_VOID(frameLoaderOwner)do { if ((__builtin_expect(!!(!(frameLoaderOwner)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "frameLoaderOwner" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1488); return; } } while (false)
;
1489
1490 RefPtr<BrowsingContext> browsingContext = frameLoader->GetBrowsingContext();
1491 NS_ENSURE_TRUE_VOID(browsingContext)do { if ((__builtin_expect(!!(!(browsingContext)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "browsingContext" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1491); return; } } while (false)
;
1492
1493 WindowGlobalParent* windowGlobalParent =
1494 browsingContext->Canonical()->GetCurrentWindowGlobal();
1495 NS_ENSURE_TRUE_VOID(windowGlobalParent)do { if ((__builtin_expect(!!(!(windowGlobalParent)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "windowGlobalParent" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1495); return; } } while (false)
;
1496
1497 // Log to console
1498 nsAutoString localizedMsg;
1499 nsTArray<nsString> params;
1500 nsresult rv = nsContentUtils::FormatLocalizedString(
1501 nsContentUtils::eDOM_PROPERTIES, "FullscreenExitWindowFocus", params,
1502 localizedMsg);
1503
1504 NS_ENSURE_SUCCESS_VOID(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_VOID(%s) failed with "
"result 0x%" "X" "%s%s%s", "rv", static_cast<uint32_t>
(__rv), name ? " (" : "", name ? name : "", name ? ")" : "");
NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1504); return; } } while (false)
;
1505
1506 Unused << nsContentUtils::ReportToConsoleByWindowID(
1507 localizedMsg, nsIScriptError::warningFlag, "DOM"_ns,
1508 windowGlobalParent->InnerWindowId(),
1509 SourceLocation(windowGlobalParent->GetDocumentURI()));
1510}
1511
1512// Ensure that when an embedded popup with a noautofocus attribute
1513// like a date picker is opened and focused, the parent page does not blur
1514static bool IsEmeddededInNoautofocusPopup(BrowsingContext& aBc) {
1515 auto* embedder = aBc.GetEmbedderElement();
1516 if (!embedder) {
1517 return false;
1518 }
1519 nsIFrame* f = embedder->GetPrimaryFrame();
1520 if (!f || !f->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
1521 return false;
1522 }
1523
1524 nsIFrame* menuPopup =
1525 nsLayoutUtils::GetClosestFrameOfType(f, LayoutFrameType::MenuPopup);
1526 MOZ_ASSERT(menuPopup, "NS_FRAME_IN_POPUP lied?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(menuPopup)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(menuPopup))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("menuPopup" " (" "NS_FRAME_IN_POPUP lied?"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1526); AnnotateMozCrashReason("MOZ_ASSERT" "(" "menuPopup" ") ("
"NS_FRAME_IN_POPUP lied?" ")"); do { *((volatile int*)__null
) = 1526; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
1527 return static_cast<nsMenuPopupFrame*>(menuPopup)
1528 ->PopupElement()
1529 .GetXULBoolAttr(nsGkAtoms::noautofocus);
1530}
1531
1532Maybe<uint64_t> nsFocusManager::SetFocusInner(Element* aNewContent,
1533 int32_t aFlags,
1534 bool aFocusChanged,
1535 bool aAdjustWidget) {
1536 // if the element is not focusable, just return and leave the focus as is
1537 RefPtr<Element> elementToFocus =
1538 FlushAndCheckIfFocusable(aNewContent, aFlags);
1539 if (!elementToFocus) {
1540 return Nothing();
1541 }
1542
1543 const RefPtr<BrowsingContext> focusedBrowsingContext =
1544 GetFocusedBrowsingContext();
1545
1546 // check if the element to focus is a frame (iframe) containing a child
1547 // document. Frames are never directly focused; instead focusing a frame
1548 // means focus what is inside the frame. To do this, the descendant content
1549 // within the frame is retrieved and that will be focused instead.
1550 nsCOMPtr<nsPIDOMWindowOuter> newWindow;
1551 nsCOMPtr<nsPIDOMWindowOuter> subWindow = GetContentWindow(elementToFocus);
1552 if (subWindow) {
1553 elementToFocus = GetFocusedDescendant(subWindow, eIncludeAllDescendants,
1554 getter_AddRefs(newWindow));
1555
1556 // since a window is being refocused, clear aFocusChanged so that the
1557 // caret position isn't updated.
1558 aFocusChanged = false;
1559 }
1560
1561 // unless it was set above, retrieve the window for the element to focus
1562 if (!newWindow) {
1563 newWindow = GetCurrentWindow(elementToFocus);
1564 }
1565
1566 RefPtr<BrowsingContext> newBrowsingContext;
1567 if (newWindow) {
1568 newBrowsingContext = newWindow->GetBrowsingContext();
1569 }
1570
1571 // if the element is already focused, just return. Note that this happens
1572 // after the frame check above so that we compare the element that will be
1573 // focused rather than the frame it is in.
1574 if (!newWindow || (newBrowsingContext == GetFocusedBrowsingContext() &&
1575 elementToFocus == mFocusedElement)) {
1576 return Nothing();
1577 }
1578
1579 MOZ_ASSERT(newBrowsingContext)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(newBrowsingContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(newBrowsingContext))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("newBrowsingContext"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1579); AnnotateMozCrashReason("MOZ_ASSERT" "(" "newBrowsingContext"
")"); do { *((volatile int*)__null) = 1579; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1580
1581 BrowsingContext* browsingContextToFocus = newBrowsingContext;
1582 if (RefPtr<nsFrameLoaderOwner> flo = do_QueryObject(elementToFocus)) {
1583 // Only look at pre-existing browsing contexts. If this function is
1584 // called during reflow, calling GetBrowsingContext() could cause frame
1585 // loader initialization at a time when it isn't safe.
1586 if (BrowsingContext* bc = flo->GetExtantBrowsingContext()) {
1587 // If focus is already in the subtree rooted at bc, return early
1588 // to match the single-process focus semantics. Otherwise, we'd
1589 // blur and immediately refocus whatever is focused.
1590 BrowsingContext* walk = focusedBrowsingContext;
1591 while (walk) {
1592 if (walk == bc) {
1593 return Nothing();
1594 }
1595 walk = walk->GetParent();
1596 }
1597 browsingContextToFocus = bc;
1598 }
1599 }
1600
1601 // don't allow focus to be placed in docshells or descendants of docshells
1602 // that are being destroyed. Also, ensure that the page hasn't been
1603 // unloaded. The prevents content from being refocused during an unload event.
1604 nsCOMPtr<nsIDocShell> newDocShell = newWindow->GetDocShell();
1605 nsCOMPtr<nsIDocShell> docShell = newDocShell;
1606 while (docShell) {
1607 bool inUnload;
1608 docShell->GetIsInUnload(&inUnload);
1609 if (inUnload) {
1610 return Nothing();
1611 }
1612
1613 bool beingDestroyed;
1614 docShell->IsBeingDestroyed(&beingDestroyed);
1615 if (beingDestroyed) {
1616 return Nothing();
1617 }
1618
1619 BrowsingContext* bc = docShell->GetBrowsingContext();
1620
1621 nsCOMPtr<nsIDocShellTreeItem> parentDsti;
1622 docShell->GetInProcessParent(getter_AddRefs(parentDsti));
1623 docShell = do_QueryInterface(parentDsti);
1624 if (!docShell && !XRE_IsParentProcess()) {
1625 // We don't have an in-process parent, but let's see if we have
1626 // an in-process ancestor or if an out-of-process ancestor
1627 // is discarded.
1628 do {
1629 bc = bc->GetParent();
1630 if (bc && bc->IsDiscarded()) {
1631 return Nothing();
1632 }
1633 } while (bc && !bc->IsInProcess());
1634 if (bc) {
1635 docShell = bc->GetDocShell();
1636 } else {
1637 docShell = nullptr;
1638 }
1639 }
1640 }
1641
1642 bool focusMovesToDifferentBC =
1643 (focusedBrowsingContext != browsingContextToFocus);
1644
1645 if (focusedBrowsingContext && focusMovesToDifferentBC &&
1646 nsContentUtils::IsHandlingKeyBoardEvent() &&
1647 !nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
1648 MOZ_ASSERT(browsingContextToFocus,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(browsingContextToFocus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(browsingContextToFocus))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("browsingContextToFocus"
" (" "BrowsingContext to focus should be non-null." ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1649); AnnotateMozCrashReason("MOZ_ASSERT" "(" "browsingContextToFocus"
") (" "BrowsingContext to focus should be non-null." ")"); do
{ *((volatile int*)__null) = 1649; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
1649 "BrowsingContext to focus should be non-null.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(browsingContextToFocus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(browsingContextToFocus))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("browsingContextToFocus"
" (" "BrowsingContext to focus should be non-null." ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1649); AnnotateMozCrashReason("MOZ_ASSERT" "(" "browsingContextToFocus"
") (" "BrowsingContext to focus should be non-null." ")"); do
{ *((volatile int*)__null) = 1649; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
1650
1651 nsIPrincipal* focusedPrincipal = nullptr;
1652 nsIPrincipal* newPrincipal = nullptr;
1653
1654 if (XRE_IsParentProcess()) {
1655 if (WindowGlobalParent* focusedWindowGlobalParent =
1656 focusedBrowsingContext->Canonical()->GetCurrentWindowGlobal()) {
1657 focusedPrincipal = focusedWindowGlobalParent->DocumentPrincipal();
1658 }
1659
1660 if (WindowGlobalParent* newWindowGlobalParent =
1661 browsingContextToFocus->Canonical()->GetCurrentWindowGlobal()) {
1662 newPrincipal = newWindowGlobalParent->DocumentPrincipal();
1663 }
1664 } else if (focusedBrowsingContext->IsInProcess() &&
1665 browsingContextToFocus->IsInProcess()) {
1666 nsCOMPtr<nsIScriptObjectPrincipal> focused =
1667 do_QueryInterface(focusedBrowsingContext->GetDOMWindow());
1668 nsCOMPtr<nsIScriptObjectPrincipal> newFocus =
1669 do_QueryInterface(browsingContextToFocus->GetDOMWindow());
1670 MOZ_ASSERT(focused && newFocus,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(focused && newFocus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(focused && newFocus)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("focused && newFocus"
" (" "BrowsingContext should always have a window here." ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1671); AnnotateMozCrashReason("MOZ_ASSERT" "(" "focused && newFocus"
") (" "BrowsingContext should always have a window here." ")"
); do { *((volatile int*)__null) = 1671; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1671 "BrowsingContext should always have a window here.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(focused && newFocus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(focused && newFocus)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("focused && newFocus"
" (" "BrowsingContext should always have a window here." ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1671); AnnotateMozCrashReason("MOZ_ASSERT" "(" "focused && newFocus"
") (" "BrowsingContext should always have a window here." ")"
); do { *((volatile int*)__null) = 1671; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1672 focusedPrincipal = focused->GetPrincipal();
1673 newPrincipal = newFocus->GetPrincipal();
1674 }
1675
1676 if (!focusedPrincipal || !newPrincipal) {
1677 return Nothing();
1678 }
1679
1680 if (!focusedPrincipal->Subsumes(newPrincipal)) {
1681 NS_WARNING("Not allowed to focus the new window!")NS_DebugBreak(NS_DEBUG_WARNING, "Not allowed to focus the new window!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1681)
;
1682 return Nothing();
1683 }
1684 }
1685
1686 // to check if the new element is in the active window, compare the
1687 // new root docshell for the new element with the active window's docshell.
1688 RefPtr<BrowsingContext> newRootBrowsingContext = nullptr;
1689 bool isElementInActiveWindow = false;
1690 if (XRE_IsParentProcess()) {
1691 nsCOMPtr<nsPIDOMWindowOuter> newRootWindow = nullptr;
1692 nsCOMPtr<nsIDocShellTreeItem> dsti = newWindow->GetDocShell();
1693 if (dsti) {
1694 nsCOMPtr<nsIDocShellTreeItem> root;
1695 dsti->GetInProcessRootTreeItem(getter_AddRefs(root));
1696 newRootWindow = root ? root->GetWindow() : nullptr;
1697
1698 isElementInActiveWindow =
1699 (mActiveWindow && newRootWindow == mActiveWindow);
1700 }
1701 if (newRootWindow) {
1702 newRootBrowsingContext = newRootWindow->GetBrowsingContext();
1703 }
1704 } else {
1705 // XXX This is wrong for `<iframe mozbrowser>` and for XUL
1706 // `<browser remote="true">`. See:
1707 // https://searchfox.org/mozilla-central/rev/8a63fc190b39ed6951abb4aef4a56487a43962bc/dom/base/nsFrameLoader.cpp#229-232
1708 newRootBrowsingContext = newBrowsingContext->Top();
1709 // to check if the new element is in the active window, compare the
1710 // new root docshell for the new element with the active window's docshell.
1711 isElementInActiveWindow =
1712 (GetActiveBrowsingContext() == newRootBrowsingContext);
1713 }
1714
1715 // Exit fullscreen if a website focuses another window
1716 if (StaticPrefs::full_screen_api_exit_on_windowRaise() &&
1717 !isElementInActiveWindow && (aFlags & FLAG_RAISE)) {
1718 if (XRE_IsParentProcess()) {
1719 if (Document* doc = mActiveWindow ? mActiveWindow->GetDoc() : nullptr) {
1720 Document::ClearPendingFullscreenRequests(doc);
1721 if (doc->GetFullscreenElement()) {
1722 LogWarningFullscreenWindowRaise(mFocusedElement);
1723 Document::AsyncExitFullscreen(doc);
1724 }
1725 }
1726 } else {
1727 BrowsingContext* activeBrowsingContext = GetActiveBrowsingContext();
1728 if (activeBrowsingContext) {
1729 nsIDocShell* shell = activeBrowsingContext->GetDocShell();
1730 if (shell) {
1731 if (Document* doc = shell->GetDocument()) {
1732 Document::ClearPendingFullscreenRequests(doc);
1733 if (doc->GetFullscreenElement()) {
1734 Document::AsyncExitFullscreen(doc);
1735 }
1736 }
1737 } else {
1738 mozilla::dom::ContentChild* contentChild =
1739 mozilla::dom::ContentChild::GetSingleton();
1740 MOZ_ASSERT(contentChild)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(contentChild)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(contentChild))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("contentChild", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1740); AnnotateMozCrashReason("MOZ_ASSERT" "(" "contentChild"
")"); do { *((volatile int*)__null) = 1740; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1741 contentChild->SendMaybeExitFullscreen(activeBrowsingContext);
1742 }
1743 }
1744 }
1745 }
1746
1747 // if the FLAG_NOSWITCHFRAME flag is used, only allow the focus to be
1748 // shifted away from the current element if the new shell to focus is
1749 // the same or an ancestor shell of the currently focused shell.
1750 bool allowFrameSwitch = !(aFlags & FLAG_NOSWITCHFRAME) ||
1751 IsSameOrAncestor(newWindow, focusedBrowsingContext);
1752
1753 // if the element is in the active window, frame switching is allowed and
1754 // the content is in a visible window, fire blur and focus events.
1755 bool sendFocusEvent =
1756 isElementInActiveWindow && allowFrameSwitch && IsWindowVisible(newWindow);
1757
1758 // Don't allow to steal the focus from chrome nodes if the caller cannot
1759 // access them.
1760 if (sendFocusEvent && mFocusedElement &&
1761 mFocusedElement->OwnerDoc() != aNewContent->OwnerDoc() &&
1762 mFocusedElement->NodePrincipal()->IsSystemPrincipal() &&
1763 !nsContentUtils::LegacyIsCallerNativeCode() &&
1764 !nsContentUtils::CanCallerAccess(mFocusedElement)) {
1765 sendFocusEvent = false;
1766 }
1767
1768 LOGCONTENT("Shift Focus: %s", elementToFocus.get())if ((__builtin_expect(!!(mozilla::detail::log_test(gFocusLog,
LogLevel::Debug)), 0))) { nsAutoCString tag("(none)"_ns); if
(elementToFocus.get()) { elementToFocus.get()->NodeInfo()
->NameAtom()->ToUTF8String(tag); } do { const ::mozilla
::LogModule* moz_real_module = gFocusLog; if ((__builtin_expect
(!!(mozilla::detail::log_test(moz_real_module, LogLevel::Debug
)), 0))) { mozilla::detail::log_print(moz_real_module, LogLevel
::Debug, "Shift Focus: %s", tag.get()); } } while (0); }
;
1769 LOGFOCUS((" Flags: %x Current Window: %p New Window: %p Current Element: %p",do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Flags: %x Current Window: %p New Window: %p Current Element: %p"
, aFlags, mFocusedWindow.get(), newWindow.get(), mFocusedElement
.get()); } } while (0)
1770 aFlags, mFocusedWindow.get(), newWindow.get(),do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Flags: %x Current Window: %p New Window: %p Current Element: %p"
, aFlags, mFocusedWindow.get(), newWindow.get(), mFocusedElement
.get()); } } while (0)
1771 mFocusedElement.get()))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Flags: %x Current Window: %p New Window: %p Current Element: %p"
, aFlags, mFocusedWindow.get(), newWindow.get(), mFocusedElement
.get()); } } while (0)
;
1772 const uint64_t actionId = GenerateFocusActionId();
1773 LOGFOCUS(do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " In Active Window: %d Moves to different BrowsingContext: %d "
"SendFocus: %d actionid: %" "l" "u", isElementInActiveWindow
, focusMovesToDifferentBC, sendFocusEvent, actionId); } } while
(0)
1774 (" In Active Window: %d Moves to different BrowsingContext: %d "do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " In Active Window: %d Moves to different BrowsingContext: %d "
"SendFocus: %d actionid: %" "l" "u", isElementInActiveWindow
, focusMovesToDifferentBC, sendFocusEvent, actionId); } } while
(0)
1775 "SendFocus: %d actionid: %" PRIu64,do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " In Active Window: %d Moves to different BrowsingContext: %d "
"SendFocus: %d actionid: %" "l" "u", isElementInActiveWindow
, focusMovesToDifferentBC, sendFocusEvent, actionId); } } while
(0)
1776 isElementInActiveWindow, focusMovesToDifferentBC, sendFocusEvent,do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " In Active Window: %d Moves to different BrowsingContext: %d "
"SendFocus: %d actionid: %" "l" "u", isElementInActiveWindow
, focusMovesToDifferentBC, sendFocusEvent, actionId); } } while
(0)
1777 actionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " In Active Window: %d Moves to different BrowsingContext: %d "
"SendFocus: %d actionid: %" "l" "u", isElementInActiveWindow
, focusMovesToDifferentBC, sendFocusEvent, actionId); } } while
(0)
;
1778
1779 if (sendFocusEvent) {
1780 Maybe<BlurredElementInfo> blurredInfo;
1781 if (mFocusedElement) {
1782 blurredInfo.emplace(*mFocusedElement);
1783 }
1784 // return if blurring fails or the focus changes during the blur
1785 if (focusedBrowsingContext) {
1786 // find the common ancestor of the currently focused window and the new
1787 // window. The ancestor will need to have its currently focused node
1788 // cleared once the document has been blurred. Otherwise, we'll be in a
1789 // state where a document is blurred yet the chain of windows above it
1790 // still points to that document.
1791 // For instance, in the following frame tree:
1792 // A
1793 // B C
1794 // D
1795 // D is focused and we want to focus C. Once D has been blurred, we need
1796 // to clear out the focus in A, otherwise A would still maintain that B
1797 // was focused, and B that D was focused.
1798 RefPtr<BrowsingContext> commonAncestor =
1799 focusMovesToDifferentBC
1800 ? GetCommonAncestor(newWindow, focusedBrowsingContext)
1801 : nullptr;
1802
1803 const bool needToClearFocusedElement = [&] {
1804 if (focusedBrowsingContext->IsChrome()) {
1805 // Always reset focused element if focus is currently in chrome
1806 // window, unless we're moving focus to a popup.
1807 return !IsEmeddededInNoautofocusPopup(*browsingContextToFocus);
1808 }
1809 if (focusedBrowsingContext->Top() != browsingContextToFocus->Top()) {
1810 // Only reset focused element if focus moves within the same top-level
1811 // content window.
1812 return false;
1813 }
1814 // XXX for the case that we try to focus an
1815 // already-focused-remote-frame, we would still send blur and focus
1816 // IPC to it, but they will not generate blur or focus event, we don't
1817 // want to reset activeElement on the remote frame.
1818 return focusMovesToDifferentBC || focusedBrowsingContext->IsInProcess();
1819 }();
1820
1821 const bool remainActive =
1822 focusMovesToDifferentBC &&
1823 IsEmeddededInNoautofocusPopup(*browsingContextToFocus);
1824
1825 // TODO: MOZ_KnownLive is required due to bug 1770680
1826 if (!Blur(MOZ_KnownLive(needToClearFocusedElement(needToClearFocusedElement ? focusedBrowsingContext.get() : nullptr
)
1827 ? focusedBrowsingContext.get()(needToClearFocusedElement ? focusedBrowsingContext.get() : nullptr
)
1828 : nullptr)(needToClearFocusedElement ? focusedBrowsingContext.get() : nullptr
)
,
1829 commonAncestor, focusMovesToDifferentBC, aAdjustWidget,
1830 remainActive, actionId, elementToFocus)) {
1831 return Some(actionId);
1832 }
1833 }
1834
1835 Focus(newWindow, elementToFocus, aFlags, focusMovesToDifferentBC,
1836 aFocusChanged, false, aAdjustWidget, actionId, blurredInfo);
1837 } else {
1838 // otherwise, for inactive windows and when the caller cannot steal the
1839 // focus, update the node in the window, and raise the window if desired.
1840 if (allowFrameSwitch) {
1841 AdjustWindowFocus(newBrowsingContext, true, IsWindowVisible(newWindow),
1842 actionId, false /* aShouldClearAncestorFocus */,
1843 nullptr /* aAncestorBrowsingContextToFocus */);
1844 }
1845
1846 // set the focus node and method as needed
1847 uint32_t focusMethod =
1848 aFocusChanged ? aFlags & METHODANDRING_MASK
1849 : newWindow->GetFocusMethod() |
1850 (aFlags & (FLAG_SHOWRING | FLAG_NOSHOWRING));
1851 newWindow->SetFocusedElement(elementToFocus, focusMethod);
1852 if (aFocusChanged) {
1853 if (nsCOMPtr<nsIDocShell> docShell = newWindow->GetDocShell()) {
1854 RefPtr<PresShell> presShell = docShell->GetPresShell();
1855 if (presShell && presShell->DidInitialize()) {
1856 ScrollIntoView(presShell, elementToFocus, aFlags);
1857 }
1858 }
1859 }
1860
1861 // update the commands even when inactive so that the attributes for that
1862 // window are up to date.
1863 if (allowFrameSwitch) {
1864 newWindow->UpdateCommands(u"focus"_ns);
1865 }
1866
1867 if (aFlags & FLAG_RAISE) {
1868 if (newRootBrowsingContext) {
1869 if (XRE_IsParentProcess() || newRootBrowsingContext->IsInProcess()) {
1870 nsCOMPtr<nsPIDOMWindowOuter> outerWindow =
1871 newRootBrowsingContext->GetDOMWindow();
1872 RaiseWindow(outerWindow,
1873 aFlags & FLAG_NONSYSTEMCALLER ? CallerType::NonSystem
1874 : CallerType::System,
1875 actionId);
1876 } else {
1877 mozilla::dom::ContentChild* contentChild =
1878 mozilla::dom::ContentChild::GetSingleton();
1879 MOZ_ASSERT(contentChild)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(contentChild)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(contentChild))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("contentChild", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1879); AnnotateMozCrashReason("MOZ_ASSERT" "(" "contentChild"
")"); do { *((volatile int*)__null) = 1879; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1880 contentChild->SendRaiseWindow(newRootBrowsingContext,
1881 aFlags & FLAG_NONSYSTEMCALLER
1882 ? CallerType::NonSystem
1883 : CallerType::System,
1884 actionId);
1885 }
1886 }
1887 }
1888 }
1889 return Some(actionId);
1890}
1891
1892static BrowsingContext* GetParentIgnoreChromeBoundary(BrowsingContext* aBC) {
1893 // Chrome BrowsingContexts are only available in the parent process, so if
1894 // we're in a content process, we only worry about the context tree.
1895 if (XRE_IsParentProcess()) {
1896 return aBC->Canonical()->GetParentCrossChromeBoundary();
1897 }
1898 return aBC->GetParent();
1899}
1900
1901bool nsFocusManager::IsSameOrAncestor(BrowsingContext* aPossibleAncestor,
1902 BrowsingContext* aContext) const {
1903 if (!aPossibleAncestor) {
1904 return false;
1905 }
1906
1907 for (BrowsingContext* bc = aContext; bc;
1908 bc = GetParentIgnoreChromeBoundary(bc)) {
1909 if (bc == aPossibleAncestor) {
1910 return true;
1911 }
1912 }
1913
1914 return false;
1915}
1916
1917bool nsFocusManager::IsSameOrAncestor(nsPIDOMWindowOuter* aPossibleAncestor,
1918 nsPIDOMWindowOuter* aWindow) const {
1919 if (aWindow && aPossibleAncestor) {
1920 return IsSameOrAncestor(aPossibleAncestor->GetBrowsingContext(),
1921 aWindow->GetBrowsingContext());
1922 }
1923 return false;
1924}
1925
1926bool nsFocusManager::IsSameOrAncestor(nsPIDOMWindowOuter* aPossibleAncestor,
1927 BrowsingContext* aContext) const {
1928 if (aPossibleAncestor) {
1929 return IsSameOrAncestor(aPossibleAncestor->GetBrowsingContext(), aContext);
1930 }
1931 return false;
1932}
1933
1934bool nsFocusManager::IsSameOrAncestor(BrowsingContext* aPossibleAncestor,
1935 nsPIDOMWindowOuter* aWindow) const {
1936 if (aWindow) {
1937 return IsSameOrAncestor(aPossibleAncestor, aWindow->GetBrowsingContext());
1938 }
1939 return false;
1940}
1941
1942mozilla::dom::BrowsingContext* nsFocusManager::GetCommonAncestor(
1943 nsPIDOMWindowOuter* aWindow, mozilla::dom::BrowsingContext* aContext) {
1944 NS_ENSURE_TRUE(aWindow && aContext, nullptr)do { if ((__builtin_expect(!!(!(aWindow && aContext))
, 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aWindow && aContext"
") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1944); return nullptr; } } while (false)
;
1945
1946 if (XRE_IsParentProcess()) {
1947 nsCOMPtr<nsIDocShellTreeItem> dsti1 = aWindow->GetDocShell();
1948 NS_ENSURE_TRUE(dsti1, nullptr)do { if ((__builtin_expect(!!(!(dsti1)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "dsti1" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1948); return nullptr; } } while (false)
;
1949
1950 nsCOMPtr<nsIDocShellTreeItem> dsti2 = aContext->GetDocShell();
1951 NS_ENSURE_TRUE(dsti2, nullptr)do { if ((__builtin_expect(!!(!(dsti2)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "dsti2" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1951); return nullptr; } } while (false)
;
1952
1953 AutoTArray<nsIDocShellTreeItem*, 30> parents1, parents2;
1954 do {
1955 parents1.AppendElement(dsti1);
1956 nsCOMPtr<nsIDocShellTreeItem> parentDsti1;
1957 dsti1->GetInProcessParent(getter_AddRefs(parentDsti1));
1958 dsti1.swap(parentDsti1);
1959 } while (dsti1);
1960 do {
1961 parents2.AppendElement(dsti2);
1962 nsCOMPtr<nsIDocShellTreeItem> parentDsti2;
1963 dsti2->GetInProcessParent(getter_AddRefs(parentDsti2));
1964 dsti2.swap(parentDsti2);
1965 } while (dsti2);
1966
1967 uint32_t pos1 = parents1.Length();
1968 uint32_t pos2 = parents2.Length();
1969 nsIDocShellTreeItem* parent = nullptr;
1970 uint32_t len;
1971 for (len = std::min(pos1, pos2); len > 0; --len) {
1972 nsIDocShellTreeItem* child1 = parents1.ElementAt(--pos1);
1973 nsIDocShellTreeItem* child2 = parents2.ElementAt(--pos2);
1974 if (child1 != child2) {
1975 break;
1976 }
1977 parent = child1;
1978 }
1979
1980 return parent ? parent->GetBrowsingContext() : nullptr;
1981 }
1982
1983 BrowsingContext* bc1 = aWindow->GetBrowsingContext();
1984 NS_ENSURE_TRUE(bc1, nullptr)do { if ((__builtin_expect(!!(!(bc1)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "bc1" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 1984); return nullptr; } } while (false)
;
1985
1986 BrowsingContext* bc2 = aContext;
1987
1988 AutoTArray<BrowsingContext*, 30> parents1, parents2;
1989 do {
1990 parents1.AppendElement(bc1);
1991 bc1 = bc1->GetParent();
1992 } while (bc1);
1993 do {
1994 parents2.AppendElement(bc2);
1995 bc2 = bc2->GetParent();
1996 } while (bc2);
1997
1998 uint32_t pos1 = parents1.Length();
1999 uint32_t pos2 = parents2.Length();
2000 BrowsingContext* parent = nullptr;
2001 uint32_t len;
2002 for (len = std::min(pos1, pos2); len > 0; --len) {
2003 BrowsingContext* child1 = parents1.ElementAt(--pos1);
2004 BrowsingContext* child2 = parents2.ElementAt(--pos2);
2005 if (child1 != child2) {
2006 break;
2007 }
2008 parent = child1;
2009 }
2010
2011 return parent;
2012}
2013
2014bool nsFocusManager::AdjustInProcessWindowFocus(
2015 BrowsingContext* aBrowsingContext, bool aCheckPermission, bool aIsVisible,
2016 uint64_t aActionId, bool aShouldClearAncestorFocus,
2017 BrowsingContext* aAncestorBrowsingContextToFocus) {
2018 MOZ_ASSERT_IF(aAncestorBrowsingContextToFocus, aShouldClearAncestorFocus)do { if (aAncestorBrowsingContextToFocus) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(aShouldClearAncestorFocus
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aShouldClearAncestorFocus))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aShouldClearAncestorFocus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 2018); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aShouldClearAncestorFocus"
")"); do { *((volatile int*)__null) = 2018; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2019 if (ActionIdComparableAndLower(aActionId,
2020 mActionIdForFocusedBrowsingContextInContent)) {
2021 LOGFOCUS(do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to adjust an in-process BrowsingContext [%p] as "
"focused from another process due to stale action id %" "l" "u"
".", aBrowsingContext, aActionId); } } while (0)
2022 ("Ignored an attempt to adjust an in-process BrowsingContext [%p] as "do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to adjust an in-process BrowsingContext [%p] as "
"focused from another process due to stale action id %" "l" "u"
".", aBrowsingContext, aActionId); } } while (0)
2023 "focused from another process due to stale action id %" PRIu64 ".",do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to adjust an in-process BrowsingContext [%p] as "
"focused from another process due to stale action id %" "l" "u"
".", aBrowsingContext, aActionId); } } while (0)
2024 aBrowsingContext, aActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to adjust an in-process BrowsingContext [%p] as "
"focused from another process due to stale action id %" "l" "u"
".", aBrowsingContext, aActionId); } } while (0)
;
2025 return false;
2026 }
2027
2028 BrowsingContext* bc = aBrowsingContext;
2029 bool needToNotifyOtherProcess = false;
2030 while (bc) {
2031 // get the containing <iframe> or equivalent element so that it can be
2032 // focused below.
2033 nsCOMPtr<Element> frameElement = bc->GetEmbedderElement();
2034 BrowsingContext* parent = bc->GetParent();
2035 if (!parent && XRE_IsParentProcess()) {
2036 CanonicalBrowsingContext* canonical = bc->Canonical();
2037 RefPtr<WindowGlobalParent> embedder =
2038 canonical->GetEmbedderWindowGlobal();
2039 if (embedder) {
2040 parent = embedder->BrowsingContext();
2041 }
2042 }
2043 bc = parent;
2044 if (!bc) {
2045 break;
2046 }
2047 if (!frameElement && XRE_IsContentProcess()) {
2048 needToNotifyOtherProcess = true;
2049 continue;
2050 }
2051
2052 nsCOMPtr<nsPIDOMWindowOuter> window = bc->GetDOMWindow();
2053 MOZ_ASSERT(window)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(window)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(window))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("window", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 2053); AnnotateMozCrashReason("MOZ_ASSERT" "(" "window" ")"
); do { *((volatile int*)__null) = 2053; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2054 // if the parent window is visible but the original window was not, then we
2055 // have likely moved up and out from a hidden tab to the browser window, or
2056 // a similar such arrangement. Stop adjusting the current nodes.
2057 if (IsWindowVisible(window) != aIsVisible) {
2058 break;
2059 }
2060
2061 // When aCheckPermission is true, we should check whether the caller can
2062 // access the window or not. If it cannot access, we should stop the
2063 // adjusting.
2064 if (aCheckPermission && !nsContentUtils::LegacyIsCallerNativeCode() &&
2065 !nsContentUtils::CanCallerAccess(window->GetCurrentInnerWindow())) {
2066 break;
2067 }
2068
2069 if (aShouldClearAncestorFocus) {
2070 // This is the BrowsingContext that receives the focus, no need to clear
2071 // its focused element and the rest of the ancestors.
2072 if (window->GetBrowsingContext() == aAncestorBrowsingContextToFocus) {
2073 break;
2074 }
2075
2076 window->SetFocusedElement(nullptr);
2077 continue;
2078 }
2079
2080 if (frameElement != window->GetFocusedElement()) {
2081 window->SetFocusedElement(frameElement);
2082
2083 RefPtr<nsFrameLoaderOwner> loaderOwner = do_QueryObject(frameElement);
2084 MOZ_ASSERT(loaderOwner)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(loaderOwner)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(loaderOwner))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("loaderOwner", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 2084); AnnotateMozCrashReason("MOZ_ASSERT" "(" "loaderOwner"
")"); do { *((volatile int*)__null) = 2084; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2085 RefPtr<nsFrameLoader> loader = loaderOwner->GetFrameLoader();
2086 if (loader && loader->IsRemoteFrame() &&
2087 GetFocusedBrowsingContext() == bc) {
2088 Blur(nullptr, nullptr, true, true, false, aActionId);
2089 }
2090 }
2091 }
2092 return needToNotifyOtherProcess;
2093}
2094
2095void nsFocusManager::AdjustWindowFocus(
2096 BrowsingContext* aBrowsingContext, bool aCheckPermission, bool aIsVisible,
2097 uint64_t aActionId, bool aShouldClearAncestorFocus,
2098 BrowsingContext* aAncestorBrowsingContextToFocus) {
2099 MOZ_ASSERT_IF(aAncestorBrowsingContextToFocus, aShouldClearAncestorFocus)do { if (aAncestorBrowsingContextToFocus) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(aShouldClearAncestorFocus
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aShouldClearAncestorFocus))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("aShouldClearAncestorFocus", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 2099); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aShouldClearAncestorFocus"
")"); do { *((volatile int*)__null) = 2099; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
2100 if (AdjustInProcessWindowFocus(aBrowsingContext, aCheckPermission, aIsVisible,
2101 aActionId, aShouldClearAncestorFocus,
2102 aAncestorBrowsingContextToFocus)) {
2103 // Some ancestors of aBrowsingContext isn't in this process, so notify other
2104 // processes to adjust their focused element.
2105 mozilla::dom::ContentChild* contentChild =
2106 mozilla::dom::ContentChild::GetSingleton();
2107 MOZ_ASSERT(contentChild)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(contentChild)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(contentChild))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("contentChild", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 2107); AnnotateMozCrashReason("MOZ_ASSERT" "(" "contentChild"
")"); do { *((volatile int*)__null) = 2107; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2108 contentChild->SendAdjustWindowFocus(aBrowsingContext, aIsVisible, aActionId,
2109 aShouldClearAncestorFocus,
2110 aAncestorBrowsingContextToFocus);
2111 }
2112}
2113
2114bool nsFocusManager::IsWindowVisible(nsPIDOMWindowOuter* aWindow) {
2115 if (!aWindow || aWindow->IsFrozen()) {
2116 return false;
2117 }
2118
2119 // Check if the inner window is frozen as well. This can happen when a focus
2120 // change occurs while restoring a previous page.
2121 nsPIDOMWindowInner* innerWindow = aWindow->GetCurrentInnerWindow();
2122 if (!innerWindow || innerWindow->IsFrozen()) {
2123 return false;
2124 }
2125
2126 nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
2127 nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(docShell));
2128 if (!baseWin) {
2129 return false;
2130 }
2131
2132 bool visible = false;
2133 baseWin->GetVisibility(&visible);
2134 return visible;
2135}
2136
2137bool nsFocusManager::IsNonFocusableRoot(nsIContent* aContent) {
2138 MOZ_ASSERT(aContent, "aContent must not be NULL")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aContent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aContent" " (" "aContent must not be NULL"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 2138); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent" ") ("
"aContent must not be NULL" ")"); do { *((volatile int*)__null
) = 2138; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
2139 MOZ_ASSERT(aContent->IsInComposedDoc(), "aContent must be in a document")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContent->IsInComposedDoc())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aContent->IsInComposedDoc
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aContent->IsInComposedDoc()" " (" "aContent must be in a document"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 2139); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContent->IsInComposedDoc()"
") (" "aContent must be in a document" ")"); do { *((volatile
int*)__null) = 2139; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
2140
2141 // If the uncomposed document of aContent is in designMode, the root element
2142 // is not focusable.
2143 // NOTE: Most elements whose uncomposed document is in design mode are not
2144 // focusable, just the document is focusable. However, if it's in a
2145 // shadow tree, it may be focus able even if the shadow host is in
2146 // design mode.
2147 // Also, if aContent is not editable and it's not in designMode, it's not
2148 // focusable.
2149 // And in userfocusignored context nothing is focusable.
2150 Document* doc = aContent->GetComposedDoc();
2151 NS_ASSERTION(doc, "aContent must have current document")do { if (!(doc)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "aContent must have current document"
, "doc", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 2151); MOZ_PretendNoReturn(); } } while (0)
;
2152 return aContent == doc->GetRootElement() &&
2153 (aContent->IsInDesignMode() || !aContent->IsEditable());
2154}
2155
2156Element* nsFocusManager::FlushAndCheckIfFocusable(Element* aElement,
2157 uint32_t aFlags) {
2158 if (!aElement) {
2159 return nullptr;
2160 }
2161
2162 nsCOMPtr<Document> doc = aElement->GetComposedDoc();
2163 // can't focus elements that are not in documents
2164 if (!doc) {
2165 LOGCONTENT("Cannot focus %s because content not in document", aElement)if ((__builtin_expect(!!(mozilla::detail::log_test(gFocusLog,
LogLevel::Debug)), 0))) { nsAutoCString tag("(none)"_ns); if
(aElement) { aElement->NodeInfo()->NameAtom()->ToUTF8String
(tag); } do { const ::mozilla::LogModule* moz_real_module = gFocusLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Cannot focus %s because content not in document"
, tag.get()); } } while (0); }
2166 return nullptr;
2167 }
2168
2169 // Make sure that our frames are up to date while ensuring the presshell is
2170 // also initialized in case we come from a script calling focus() early.
2171 mEventHandlingNeedsFlush = false;
2172 doc->FlushPendingNotifications(FlushType::EnsurePresShellInitAndFrames);
2173
2174 PresShell* presShell = doc->GetPresShell();
2175 if (!presShell) {
2176 return nullptr;
2177 }
2178
2179 // If this is an iframe that doesn't have an in-process subdocument, it is
2180 // either an OOP iframe or an in-process iframe without lazy about:blank
2181 // creation having taken place. In the OOP case, iframe is always focusable.
2182 // In the in-process case, create the initial about:blank for in-process
2183 // BrowsingContexts in order to have the `GetSubDocumentFor` call after this
2184 // block return something.
2185 //
2186 // TODO(emilio): This block can probably go after bug 543435 lands.
2187 if (RefPtr<nsFrameLoaderOwner> flo = do_QueryObject(aElement)) {
2188 if (!aElement->IsXULElement()) {
2189 // Only look at pre-existing browsing contexts. If this function is
2190 // called during reflow, calling GetBrowsingContext() could cause frame
2191 // loader initialization at a time when it isn't safe.
2192 if (BrowsingContext* bc = flo->GetExtantBrowsingContext()) {
2193 // This call may create a contentViewer-created about:blank.
2194 // That's intentional, so we can move focus there.
2195 Unused << bc->GetDocument();
2196 }
2197 }
2198 }
2199
2200 return GetTheFocusableArea(aElement, aFlags);
2201}
2202
2203bool nsFocusManager::Blur(BrowsingContext* aBrowsingContextToClear,
2204 BrowsingContext* aAncestorBrowsingContextToFocus,
2205 bool aIsLeavingDocument, bool aAdjustWidget,
2206 bool aRemainActive, uint64_t aActionId,
2207 Element* aElementToFocus) {
2208 if (XRE_IsParentProcess()) {
2209 return BlurImpl(aBrowsingContextToClear, aAncestorBrowsingContextToFocus,
2210 aIsLeavingDocument, aAdjustWidget, aRemainActive,
2211 aElementToFocus, aActionId);
2212 }
2213 mozilla::dom::ContentChild* contentChild =
2214 mozilla::dom::ContentChild::GetSingleton();
2215 MOZ_ASSERT(contentChild)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(contentChild)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(contentChild))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("contentChild", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 2215); AnnotateMozCrashReason("MOZ_ASSERT" "(" "contentChild"
")"); do { *((volatile int*)__null) = 2215; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2216 bool windowToClearHandled = false;
2217 bool ancestorWindowToFocusHandled = false;
2218
2219 RefPtr<BrowsingContext> focusedBrowsingContext = GetFocusedBrowsingContext();
2220 if (focusedBrowsingContext && focusedBrowsingContext->IsDiscarded()) {
2221 focusedBrowsingContext = nullptr;
2222 }
2223 if (!focusedBrowsingContext) {
2224 mFocusedElement = nullptr;
2225 return true;
2226 }
2227 if (aBrowsingContextToClear && aBrowsingContextToClear->IsDiscarded()) {
2228 aBrowsingContextToClear = nullptr;
2229 }
2230 if (aAncestorBrowsingContextToFocus &&
2231 aAncestorBrowsingContextToFocus->IsDiscarded()) {
2232 aAncestorBrowsingContextToFocus = nullptr;
2233 }
2234 // XXX should more early returns from BlurImpl be hoisted here to avoid
2235 // processing aBrowsingContextToClear and aAncestorBrowsingContextToFocus in
2236 // other processes when BlurImpl returns early in this process? Or should the
2237 // IPC messages for those be sent by BlurImpl itself, in which case they could
2238 // arrive late?
2239 if (focusedBrowsingContext->IsInProcess()) {
2240 if (aBrowsingContextToClear && !aBrowsingContextToClear->IsInProcess()) {
2241 MOZ_RELEASE_ASSERT(!(aAncestorBrowsingContextToFocus &&do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(aAncestorBrowsingContextToFocus && !aAncestorBrowsingContextToFocus
->IsInProcess()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(aAncestorBrowsingContextToFocus
&& !aAncestorBrowsingContextToFocus->IsInProcess(
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(aAncestorBrowsingContextToFocus && !aAncestorBrowsingContextToFocus->IsInProcess())"
" (" "Both aBrowsingContextToClear and " "aAncestorBrowsingContextToFocus are "
"out-of-process." ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 2245); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!(aAncestorBrowsingContextToFocus && !aAncestorBrowsingContextToFocus->IsInProcess())"
") (" "Both aBrowsingContextToClear and " "aAncestorBrowsingContextToFocus are "
"out-of-process." ")"); do { *((volatile int*)__null) = 2245
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
2242 !aAncestorBrowsingContextToFocus->IsInProcess()),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(aAncestorBrowsingContextToFocus && !aAncestorBrowsingContextToFocus
->IsInProcess()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(aAncestorBrowsingContextToFocus
&& !aAncestorBrowsingContextToFocus->IsInProcess(
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(aAncestorBrowsingContextToFocus && !aAncestorBrowsingContextToFocus->IsInProcess())"
" (" "Both aBrowsingContextToClear and " "aAncestorBrowsingContextToFocus are "
"out-of-process." ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 2245); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!(aAncestorBrowsingContextToFocus && !aAncestorBrowsingContextToFocus->IsInProcess())"
") (" "Both aBrowsingContextToClear and " "aAncestorBrowsingContextToFocus are "
"out-of-process." ")"); do { *((volatile int*)__null) = 2245
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
2243 "Both aBrowsingContextToClear and "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(aAncestorBrowsingContextToFocus && !aAncestorBrowsingContextToFocus
->IsInProcess()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(aAncestorBrowsingContextToFocus
&& !aAncestorBrowsingContextToFocus->IsInProcess(
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(aAncestorBrowsingContextToFocus && !aAncestorBrowsingContextToFocus->IsInProcess())"
" (" "Both aBrowsingContextToClear and " "aAncestorBrowsingContextToFocus are "
"out-of-process." ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 2245); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!(aAncestorBrowsingContextToFocus && !aAncestorBrowsingContextToFocus->IsInProcess())"
") (" "Both aBrowsingContextToClear and " "aAncestorBrowsingContextToFocus are "
"out-of-process." ")"); do { *((volatile int*)__null) = 2245
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
2244 "aAncestorBrowsingContextToFocus are "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(aAncestorBrowsingContextToFocus && !aAncestorBrowsingContextToFocus
->IsInProcess()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(aAncestorBrowsingContextToFocus
&& !aAncestorBrowsingContextToFocus->IsInProcess(
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(aAncestorBrowsingContextToFocus && !aAncestorBrowsingContextToFocus->IsInProcess())"
" (" "Both aBrowsingContextToClear and " "aAncestorBrowsingContextToFocus are "
"out-of-process." ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 2245); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!(aAncestorBrowsingContextToFocus && !aAncestorBrowsingContextToFocus->IsInProcess())"
") (" "Both aBrowsingContextToClear and " "aAncestorBrowsingContextToFocus are "
"out-of-process." ")"); do { *((volatile int*)__null) = 2245
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
2245 "out-of-process.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!(aAncestorBrowsingContextToFocus && !aAncestorBrowsingContextToFocus
->IsInProcess()))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!(aAncestorBrowsingContextToFocus
&& !aAncestorBrowsingContextToFocus->IsInProcess(
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!(aAncestorBrowsingContextToFocus && !aAncestorBrowsingContextToFocus->IsInProcess())"
" (" "Both aBrowsingContextToClear and " "aAncestorBrowsingContextToFocus are "
"out-of-process." ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 2245); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "!(aAncestorBrowsingContextToFocus && !aAncestorBrowsingContextToFocus->IsInProcess())"
") (" "Both aBrowsingContextToClear and " "aAncestorBrowsingContextToFocus are "
"out-of-process." ")"); do { *((volatile int*)__null) = 2245
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
2246 contentChild->SendSetFocusedElement(aBrowsingContextToClear, false);
2247 }
2248 if (aAncestorBrowsingContextToFocus &&
2249 !aAncestorBrowsingContextToFocus->IsInProcess()) {
2250 contentChild->SendSetFocusedElement(aAncestorBrowsingContextToFocus,
2251 true);
2252 }
2253 return BlurImpl(aBrowsingContextToClear, aAncestorBrowsingContextToFocus,
2254 aIsLeavingDocument, aAdjustWidget, aRemainActive,
2255 aElementToFocus, aActionId);
2256 }
2257 if (aBrowsingContextToClear && aBrowsingContextToClear->IsInProcess()) {
2258 nsPIDOMWindowOuter* windowToClear = aBrowsingContextToClear->GetDOMWindow();
2259 MOZ_ASSERT(windowToClear)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(windowToClear)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(windowToClear))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("windowToClear",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 2259); AnnotateMozCrashReason("MOZ_ASSERT" "(" "windowToClear"
")"); do { *((volatile int*)__null) = 2259; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2260 windowToClear->SetFocusedElement(nullptr);
2261 windowToClearHandled = true;
2262 }
2263 if (aAncestorBrowsingContextToFocus &&
2264 aAncestorBrowsingContextToFocus->IsInProcess()) {
2265 nsPIDOMWindowOuter* ancestorWindowToFocus =
2266 aAncestorBrowsingContextToFocus->GetDOMWindow();
2267 MOZ_ASSERT(ancestorWindowToFocus)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ancestorWindowToFocus)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ancestorWindowToFocus))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("ancestorWindowToFocus"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 2267); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ancestorWindowToFocus"
")"); do { *((volatile int*)__null) = 2267; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2268 ancestorWindowToFocus->SetFocusedElement(nullptr, 0, true);
2269 ancestorWindowToFocusHandled = true;
2270 }
2271 // The expectation is that the blurring would eventually result in an IPC
2272 // message doing this anyway, but this doesn't happen if the focus is in OOP
2273 // iframe which won't try to bounce an IPC message to its parent frame.
2274 SetFocusedWindowInternal(nullptr, aActionId);
2275 contentChild->SendBlurToParent(
2276 focusedBrowsingContext, aBrowsingContextToClear,
2277 aAncestorBrowsingContextToFocus, aIsLeavingDocument, aAdjustWidget,
2278 windowToClearHandled, ancestorWindowToFocusHandled, aActionId);
2279 return true;
2280}
2281
2282void nsFocusManager::BlurFromOtherProcess(
2283 mozilla::dom::BrowsingContext* aFocusedBrowsingContext,
2284 mozilla::dom::BrowsingContext* aBrowsingContextToClear,
2285 mozilla::dom::BrowsingContext* aAncestorBrowsingContextToFocus,
2286 bool aIsLeavingDocument, bool aAdjustWidget, uint64_t aActionId) {
2287 if (aFocusedBrowsingContext != GetFocusedBrowsingContext()) {
2288 return;
2289 }
2290 BlurImpl(aBrowsingContextToClear, aAncestorBrowsingContextToFocus,
2291 aIsLeavingDocument, aAdjustWidget, /* aRemainActive = */ false,
2292 nullptr, aActionId);
2293}
2294
2295bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear,
2296 BrowsingContext* aAncestorBrowsingContextToFocus,
2297 bool aIsLeavingDocument, bool aAdjustWidget,
2298 bool aRemainActive, Element* aElementToFocus,
2299 uint64_t aActionId) {
2300 LOGFOCUS(("<<Blur begin actionid: %" PRIu64 ">>", aActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "<<Blur begin actionid: %"
"l" "u" ">>", aActionId); } } while (0)
;
2301
2302 // hold a reference to the focused content, which may be null
2303 RefPtr<Element> element = mFocusedElement;
2304 if (element) {
2305 if (!element->IsInComposedDoc()) {
2306 mFocusedElement = nullptr;
2307 return true;
2308 }
2309 if (element == mFirstBlurEvent) {
2310 return true;
2311 }
2312 }
2313
2314 RefPtr<BrowsingContext> focusedBrowsingContext = GetFocusedBrowsingContext();
2315 // hold a reference to the focused window
2316 nsCOMPtr<nsPIDOMWindowOuter> window;
2317 if (focusedBrowsingContext) {
2318 window = focusedBrowsingContext->GetDOMWindow();
2319 }
2320 if (!window) {
2321 mFocusedElement = nullptr;
2322 return true;
2323 }
2324
2325 nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
2326 if (!docShell) {
2327 if (XRE_IsContentProcess() &&
2328 ActionIdComparableAndLower(
2329 aActionId, mActionIdForFocusedBrowsingContextInContent)) {
2330 // Unclear if this ever happens.
2331 LOGFOCUS(do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to null out focused BrowsingContext when "
"docShell is null due to a stale action id %" "l" "u" ".", aActionId
); } } while (0)
2332 ("Ignored an attempt to null out focused BrowsingContext when "do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to null out focused BrowsingContext when "
"docShell is null due to a stale action id %" "l" "u" ".", aActionId
); } } while (0)
2333 "docShell is null due to a stale action id %" PRIu64 ".",do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to null out focused BrowsingContext when "
"docShell is null due to a stale action id %" "l" "u" ".", aActionId
); } } while (0)
2334 aActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to null out focused BrowsingContext when "
"docShell is null due to a stale action id %" "l" "u" ".", aActionId
); } } while (0)
;
2335 return true;
2336 }
2337
2338 mFocusedWindow = nullptr;
2339 // Setting focused BrowsingContext to nullptr to avoid leaking in print
2340 // preview.
2341 SetFocusedBrowsingContext(nullptr, aActionId);
2342 mFocusedElement = nullptr;
2343 return true;
2344 }
2345
2346 // Keep a ref to presShell since dispatching the DOM event may cause
2347 // the document to be destroyed.
2348 RefPtr<PresShell> presShell = docShell->GetPresShell();
2349 if (!presShell) {
2350 if (XRE_IsContentProcess() &&
2351 ActionIdComparableAndLower(
2352 aActionId, mActionIdForFocusedBrowsingContextInContent)) {
2353 // Unclear if this ever happens.
2354 LOGFOCUS(do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to null out focused BrowsingContext when "
"presShell is null due to a stale action id %" "l" "u" ".", aActionId
); } } while (0)
2355 ("Ignored an attempt to null out focused BrowsingContext when "do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to null out focused BrowsingContext when "
"presShell is null due to a stale action id %" "l" "u" ".", aActionId
); } } while (0)
2356 "presShell is null due to a stale action id %" PRIu64 ".",do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to null out focused BrowsingContext when "
"presShell is null due to a stale action id %" "l" "u" ".", aActionId
); } } while (0)
2357 aActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to null out focused BrowsingContext when "
"presShell is null due to a stale action id %" "l" "u" ".", aActionId
); } } while (0)
;
2358 return true;
2359 }
2360 mFocusedElement = nullptr;
2361 mFocusedWindow = nullptr;
2362 // Setting focused BrowsingContext to nullptr to avoid leaking in print
2363 // preview.
2364 SetFocusedBrowsingContext(nullptr, aActionId);
2365 return true;
2366 }
2367
2368 Maybe<AutoRestore<RefPtr<Element>>> ar;
2369 if (!mFirstBlurEvent) {
2370 ar.emplace(mFirstBlurEvent);
2371 mFirstBlurEvent = element;
2372 }
2373
2374 const RefPtr<nsPresContext> focusedPresContext =
2375 GetActiveBrowsingContext() ? presShell->GetPresContext() : nullptr;
2376 IMEStateManager::OnChangeFocus(focusedPresContext, nullptr,
2377 GetFocusMoveActionCause(0));
2378
2379 // now adjust the actual focus, by clearing the fields in the focus manager
2380 // and in the window.
2381 mFocusedElement = nullptr;
2382 if (aBrowsingContextToClear) {
2383 nsPIDOMWindowOuter* windowToClear = aBrowsingContextToClear->GetDOMWindow();
2384 if (windowToClear) {
2385 windowToClear->SetFocusedElement(nullptr);
2386 }
2387 }
2388
2389 LOGCONTENT("Element %s has been blurred", element.get())if ((__builtin_expect(!!(mozilla::detail::log_test(gFocusLog,
LogLevel::Debug)), 0))) { nsAutoCString tag("(none)"_ns); if
(element.get()) { element.get()->NodeInfo()->NameAtom(
)->ToUTF8String(tag); } do { const ::mozilla::LogModule* moz_real_module
= gFocusLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, LogLevel::Debug)), 0))) { mozilla::detail::
log_print(moz_real_module, LogLevel::Debug, "Element %s has been blurred"
, tag.get()); } } while (0); }
;
2390
2391 // Don't fire blur event on the root content which isn't editable.
2392 bool sendBlurEvent =
2393 element && element->IsInComposedDoc() && !IsNonFocusableRoot(element);
2394 if (element) {
2395 if (sendBlurEvent) {
2396 NotifyFocusStateChange(element, aElementToFocus, 0, false, false);
2397 }
2398
2399 if (!aRemainActive) {
2400 bool windowBeingLowered = !aBrowsingContextToClear &&
2401 !aAncestorBrowsingContextToFocus &&
2402 aIsLeavingDocument && aAdjustWidget;
2403 // If the object being blurred is a remote browser, deactivate remote
2404 // content
2405 if (BrowserParent* remote = BrowserParent::GetFrom(element)) {
2406 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 2406); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 2406; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2407 // Let's deactivate all remote browsers.
2408 BrowsingContext* topLevelBrowsingContext = remote->GetBrowsingContext();
2409 topLevelBrowsingContext->PreOrderWalk([&](BrowsingContext* aContext) {
2410 if (WindowGlobalParent* windowGlobalParent =
2411 aContext->Canonical()->GetCurrentWindowGlobal()) {
2412 if (RefPtr<BrowserParent> browserParent =
2413 windowGlobalParent->GetBrowserParent()) {
2414 browserParent->Deactivate(windowBeingLowered, aActionId);
2415 LOGFOCUS(do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "%s remote browser deactivated %p, %d, actionid: %"
"l" "u", aContext == topLevelBrowsingContext ? "Top-level" :
"OOP iframe", browserParent.get(), windowBeingLowered, aActionId
); } } while (0)
2416 ("%s remote browser deactivated %p, %d, actionid: %" PRIu64,do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "%s remote browser deactivated %p, %d, actionid: %"
"l" "u", aContext == topLevelBrowsingContext ? "Top-level" :
"OOP iframe", browserParent.get(), windowBeingLowered, aActionId
); } } while (0)
2417 aContext == topLevelBrowsingContext ? "Top-level"do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "%s remote browser deactivated %p, %d, actionid: %"
"l" "u", aContext == topLevelBrowsingContext ? "Top-level" :
"OOP iframe", browserParent.get(), windowBeingLowered, aActionId
); } } while (0)
2418 : "OOP iframe",do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "%s remote browser deactivated %p, %d, actionid: %"
"l" "u", aContext == topLevelBrowsingContext ? "Top-level" :
"OOP iframe", browserParent.get(), windowBeingLowered, aActionId
); } } while (0)
2419 browserParent.get(), windowBeingLowered, aActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "%s remote browser deactivated %p, %d, actionid: %"
"l" "u", aContext == topLevelBrowsingContext ? "Top-level" :
"OOP iframe", browserParent.get(), windowBeingLowered, aActionId
); } } while (0)
;
2420 }
2421 }
2422 });
2423 }
2424
2425 // Same as above but for out-of-process iframes
2426 if (BrowserBridgeChild* bbc = BrowserBridgeChild::GetFrom(element)) {
2427 bbc->Deactivate(windowBeingLowered, aActionId);
2428 LOGFOCUS(do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Out-of-process iframe deactivated %p, %d, actionid: %"
"l" "u", bbc, windowBeingLowered, aActionId); } } while (0)
2429 ("Out-of-process iframe deactivated %p, %d, actionid: %" PRIu64,do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Out-of-process iframe deactivated %p, %d, actionid: %"
"l" "u", bbc, windowBeingLowered, aActionId); } } while (0)
2430 bbc, windowBeingLowered, aActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Out-of-process iframe deactivated %p, %d, actionid: %"
"l" "u", bbc, windowBeingLowered, aActionId); } } while (0)
;
2431 }
2432 }
2433 }
2434
2435 bool result = true;
2436 if (sendBlurEvent) {
2437 // if there is an active window, update commands. If there isn't an active
2438 // window, then this was a blur caused by the active window being lowered,
2439 // so there is no need to update the commands
2440 if (GetActiveBrowsingContext()) {
2441 window->UpdateCommands(u"focus"_ns);
2442 }
2443
2444 SendFocusOrBlurEvent(eBlur, presShell, element->GetComposedDoc(), element,
2445 false, false, aElementToFocus);
2446 }
2447
2448 // if we are leaving the document or the window was lowered, make the caret
2449 // invisible.
2450 if (aIsLeavingDocument || !GetActiveBrowsingContext()) {
2451 SetCaretVisible(presShell, false, nullptr);
2452 }
2453
2454 RefPtr<AccessibleCaretEventHub> eventHub =
2455 presShell->GetAccessibleCaretEventHub();
2456 if (eventHub) {
2457 eventHub->NotifyBlur(aIsLeavingDocument || !GetActiveBrowsingContext());
2458 }
2459
2460 // at this point, it is expected that this window will be still be
2461 // focused, but the focused element will be null, as it was cleared before
2462 // the event. If this isn't the case, then something else was focused during
2463 // the blur event above and we should just return. However, if
2464 // aIsLeavingDocument is set, a new document is desired, so make sure to
2465 // blur the document and window.
2466 if (GetFocusedBrowsingContext() != window->GetBrowsingContext() ||
2467 (mFocusedElement != nullptr && !aIsLeavingDocument)) {
2468 result = false;
2469 } else if (aIsLeavingDocument) {
2470 window->TakeFocus(false, 0);
2471
2472 // clear the focus so that the ancestor frame hierarchy is in the correct
2473 // state. Pass true because aAncestorBrowsingContextToFocus is thought to be
2474 // focused at this point.
2475 if (aAncestorBrowsingContextToFocus) {
2476 nsPIDOMWindowOuter* ancestorWindowToFocus =
2477 aAncestorBrowsingContextToFocus->GetDOMWindow();
2478 if (ancestorWindowToFocus) {
2479 ancestorWindowToFocus->SetFocusedElement(nullptr, 0, true);
2480 }
2481
2482 // When the focus of aBrowsingContextToClear is cleared, it should
2483 // also clear its ancestors's focus because ancestors should no longer
2484 // be considered aBrowsingContextToClear is focused.
2485 //
2486 // We don't need to do this when aBrowsingContextToClear and
2487 // aAncestorBrowsingContextToFocus is equal because ancestors don't
2488 // care about this.
2489 if (aBrowsingContextToClear &&
2490 aBrowsingContextToClear != aAncestorBrowsingContextToFocus) {
2491 AdjustWindowFocus(
2492 aBrowsingContextToClear, false,
2493 IsWindowVisible(aBrowsingContextToClear->GetDOMWindow()), aActionId,
2494 true /* aShouldClearAncestorFocus */,
2495 aAncestorBrowsingContextToFocus);
2496 }
2497 }
2498
2499 SetFocusedWindowInternal(nullptr, aActionId);
2500 mFocusedElement = nullptr;
2501
2502 RefPtr<Document> doc = window->GetExtantDoc();
2503 if (doc) {
2504 SendFocusOrBlurEvent(eBlur, presShell, doc, doc, false);
2505 }
2506 if (!GetFocusedBrowsingContext()) {
2507 nsCOMPtr<nsPIDOMWindowInner> innerWindow =
2508 window->GetCurrentInnerWindow();
2509 // MOZ_KnownLive due to bug 1506441
2510 SendFocusOrBlurEvent(
2511 eBlur, presShell, doc,
2512 MOZ_KnownLive(nsGlobalWindowInner::Cast(innerWindow))(nsGlobalWindowInner::Cast(innerWindow)), false);
2513 }
2514
2515 // check if a different window was focused
2516 result = (!GetFocusedBrowsingContext() && GetActiveBrowsingContext());
2517 } else if (GetActiveBrowsingContext()) {
2518 // Otherwise, the blur of the element without blurring the document
2519 // occurred normally. Call UpdateCaret to redisplay the caret at the right
2520 // location within the document. This is needed to ensure that the caret
2521 // used for caret browsing is made visible again when an input field is
2522 // blurred.
2523 UpdateCaret(false, true, nullptr);
2524 }
2525
2526 return result;
2527}
2528
2529void nsFocusManager::ActivateRemoteFrameIfNeeded(Element& aElement,
2530 uint64_t aActionId) {
2531 if (BrowserParent* remote = BrowserParent::GetFrom(&aElement)) {
2532 remote->Activate(aActionId);
2533 LOGFOCUS(do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Remote browser activated %p, actionid: %"
"l" "u", remote, aActionId); } } while (0)
2534 ("Remote browser activated %p, actionid: %" PRIu64, remote, aActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Remote browser activated %p, actionid: %"
"l" "u", remote, aActionId); } } while (0)
;
2535 }
2536
2537 // Same as above but for out-of-process iframes
2538 if (BrowserBridgeChild* bbc = BrowserBridgeChild::GetFrom(&aElement)) {
2539 bbc->Activate(aActionId);
2540 LOGFOCUS(("Out-of-process iframe activated %p, actionid: %" PRIu64, bbc,do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Out-of-process iframe activated %p, actionid: %"
"l" "u", bbc, aActionId); } } while (0)
2541 aActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Out-of-process iframe activated %p, actionid: %"
"l" "u", bbc, aActionId); } } while (0)
;
2542 }
2543}
2544
2545void nsFocusManager::Focus(
2546 nsPIDOMWindowOuter* aWindow, Element* aElement, uint32_t aFlags,
2547 bool aIsNewDocument, bool aFocusChanged, bool aWindowRaised,
2548 bool aAdjustWidget, uint64_t aActionId,
2549 const Maybe<BlurredElementInfo>& aBlurredElementInfo) {
2550 LOGFOCUS(("<<Focus begin actionid: %" PRIu64 ">>", aActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "<<Focus begin actionid: %"
"l" "u" ">>", aActionId); } } while (0)
;
2551
2552 if (!aWindow) {
2553 return;
2554 }
2555
2556 if (aElement &&
2557 (aElement == mFirstFocusEvent || aElement == mFirstBlurEvent)) {
2558 return;
2559 }
2560
2561 // Keep a reference to the presShell since dispatching the DOM event may
2562 // cause the document to be destroyed.
2563 nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
2564 if (!docShell) {
2565 return;
2566 }
2567
2568 const RefPtr<PresShell> presShell = docShell->GetPresShell();
2569 if (!presShell) {
2570 return;
2571 }
2572
2573 bool focusInOtherContentProcess = false;
2574 // Keep mochitest-browser-chrome harness happy by ignoring
2575 // focusInOtherContentProcess in the chrome process, because the harness
2576 // expects that.
2577 if (!XRE_IsParentProcess()) {
2578 if (RefPtr<nsFrameLoaderOwner> flo = do_QueryObject(aElement)) {
2579 // Only look at pre-existing browsing contexts. If this function is
2580 // called during reflow, calling GetBrowsingContext() could cause frame
2581 // loader initialization at a time when it isn't safe.
2582 if (BrowsingContext* bc = flo->GetExtantBrowsingContext()) {
2583 focusInOtherContentProcess = !bc->IsInProcess();
2584 }
2585 }
2586
2587 if (ActionIdComparableAndLower(
2588 aActionId, mActionIdForFocusedBrowsingContextInContent)) {
2589 // Unclear if this ever happens.
2590 LOGFOCUS(do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to focus an element due to stale action id "
"%" "l" "u" ".", aActionId); } } while (0)
2591 ("Ignored an attempt to focus an element due to stale action id "do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to focus an element due to stale action id "
"%" "l" "u" ".", aActionId); } } while (0)
2592 "%" PRIu64 ".",do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to focus an element due to stale action id "
"%" "l" "u" ".", aActionId); } } while (0)
2593 aActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to focus an element due to stale action id "
"%" "l" "u" ".", aActionId); } } while (0)
;
2594 return;
2595 }
2596 }
2597
2598 // If the focus actually changed, set the focus method (mouse, keyboard, etc).
2599 // Otherwise, just get the current focus method and use that. This ensures
2600 // that the method is set during the document and window focus events.
2601 uint32_t focusMethod = aFocusChanged
2602 ? aFlags & METHODANDRING_MASK
2603 : aWindow->GetFocusMethod() |
2604 (aFlags & (FLAG_SHOWRING | FLAG_NOSHOWRING));
2605
2606 if (!IsWindowVisible(aWindow)) {
2607 // if the window isn't visible, for instance because it is a hidden tab,
2608 // update the current focus and scroll it into view but don't do anything
2609 // else
2610 if (RefPtr elementToFocus = FlushAndCheckIfFocusable(aElement, aFlags)) {
2611 aWindow->SetFocusedElement(elementToFocus, focusMethod);
2612 if (aFocusChanged) {
2613 ScrollIntoView(presShell, elementToFocus, aFlags);
2614 }
2615 }
2616 return;
2617 }
2618
2619 Maybe<AutoRestore<RefPtr<Element>>> ar;
2620 if (!mFirstFocusEvent) {
2621 ar.emplace(mFirstFocusEvent);
2622 mFirstFocusEvent = aElement;
2623 }
2624
2625 LOGCONTENT("Element %s has been focused", aElement)if ((__builtin_expect(!!(mozilla::detail::log_test(gFocusLog,
LogLevel::Debug)), 0))) { nsAutoCString tag("(none)"_ns); if
(aElement) { aElement->NodeInfo()->NameAtom()->ToUTF8String
(tag); } do { const ::mozilla::LogModule* moz_real_module = gFocusLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, LogLevel::Debug)), 0))) { mozilla::detail::log_print(moz_real_module
, LogLevel::Debug, "Element %s has been focused", tag.get());
} } while (0); }
;
2626
2627 if (MOZ_LOG_TEST(gFocusLog, LogLevel::Debug)(__builtin_expect(!!(mozilla::detail::log_test(gFocusLog, LogLevel
::Debug)), 0))
) {
2628 Document* docm = aWindow->GetExtantDoc();
2629 if (docm) {
2630 LOGCONTENT(" from %s", docm->GetRootElement())if ((__builtin_expect(!!(mozilla::detail::log_test(gFocusLog,
LogLevel::Debug)), 0))) { nsAutoCString tag("(none)"_ns); if
(docm->GetRootElement()) { docm->GetRootElement()->
NodeInfo()->NameAtom()->ToUTF8String(tag); } do { const
::mozilla::LogModule* moz_real_module = gFocusLog; if ((__builtin_expect
(!!(mozilla::detail::log_test(moz_real_module, LogLevel::Debug
)), 0))) { mozilla::detail::log_print(moz_real_module, LogLevel
::Debug, " from %s", tag.get()); } } while (0); }
;
2631 }
2632 LOGFOCUS(do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " [Newdoc: %d FocusChanged: %d Raised: %d Flags: %x actionid: %"
"l" "u" "]", aIsNewDocument, aFocusChanged, aWindowRaised, aFlags
, aActionId); } } while (0)
2633 (" [Newdoc: %d FocusChanged: %d Raised: %d Flags: %x actionid: %" PRIu64do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " [Newdoc: %d FocusChanged: %d Raised: %d Flags: %x actionid: %"
"l" "u" "]", aIsNewDocument, aFocusChanged, aWindowRaised, aFlags
, aActionId); } } while (0)
2634 "]",do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " [Newdoc: %d FocusChanged: %d Raised: %d Flags: %x actionid: %"
"l" "u" "]", aIsNewDocument, aFocusChanged, aWindowRaised, aFlags
, aActionId); } } while (0)
2635 aIsNewDocument, aFocusChanged, aWindowRaised, aFlags, aActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " [Newdoc: %d FocusChanged: %d Raised: %d Flags: %x actionid: %"
"l" "u" "]", aIsNewDocument, aFocusChanged, aWindowRaised, aFlags
, aActionId); } } while (0)
;
2636 }
2637
2638 if (aIsNewDocument) {
2639 // if this is a new document, update the parent chain of frames so that
2640 // focus can be traversed from the top level down to the newly focused
2641 // window.
2642 RefPtr<BrowsingContext> bc = aWindow->GetBrowsingContext();
2643 AdjustWindowFocus(bc, false, IsWindowVisible(aWindow), aActionId,
2644 false /* aShouldClearAncestorFocus */,
2645 nullptr /* aAncestorBrowsingContextToFocus */);
2646 }
2647
2648 // indicate that the window has taken focus.
2649 if (aWindow->TakeFocus(true, focusMethod)) {
2650 aIsNewDocument = true;
2651 }
2652
2653 SetFocusedWindowInternal(aWindow, aActionId);
2654
2655 if (aAdjustWidget && !sTestMode) {
2656 if (nsViewManager* vm = presShell->GetViewManager()) {
2657 nsCOMPtr<nsIWidget> widget = vm->GetRootWidget();
2658 if (widget)
2659 widget->SetFocus(nsIWidget::Raise::No, aFlags & FLAG_NONSYSTEMCALLER
2660 ? CallerType::NonSystem
2661 : CallerType::System);
2662 }
2663 }
2664
2665 // if switching to a new document, first fire the focus event on the
2666 // document and then the window.
2667 if (aIsNewDocument) {
2668 RefPtr<Document> doc = aWindow->GetExtantDoc();
2669 // The focus change should be notified to IMEStateManager from here if:
2670 // * the focused element is in design mode or
2671 // * nobody gets focus and the document is in design mode
2672 // since any element whose uncomposed document is in design mode won't
2673 // receive focus event.
2674 if (doc && ((aElement && aElement->IsInDesignMode()) ||
2675 (!aElement && doc->IsInDesignMode()))) {
2676 RefPtr<nsPresContext> presContext = presShell->GetPresContext();
2677 IMEStateManager::OnChangeFocus(presContext, nullptr,
2678 GetFocusMoveActionCause(aFlags));
2679 }
2680 if (doc && !focusInOtherContentProcess) {
2681 SendFocusOrBlurEvent(eFocus, presShell, doc, doc, aWindowRaised);
2682 }
2683 if (GetFocusedBrowsingContext() == aWindow->GetBrowsingContext() &&
2684 !mFocusedElement && !focusInOtherContentProcess) {
2685 nsCOMPtr<nsPIDOMWindowInner> innerWindow =
2686 aWindow->GetCurrentInnerWindow();
2687 // MOZ_KnownLive due to bug 1506441
2688 SendFocusOrBlurEvent(
2689 eFocus, presShell, doc,
2690 MOZ_KnownLive(nsGlobalWindowInner::Cast(innerWindow))(nsGlobalWindowInner::Cast(innerWindow)), aWindowRaised);
2691 }
2692 }
2693
2694 // check to ensure that the element is still focusable, and that nothing
2695 // else was focused during the events above.
2696 // Note that the focusing element may have already been moved to another
2697 // document/window. In that case, we should stop setting focus to it
2698 // because setting focus to the new window would cause redirecting focus
2699 // again and again.
2700 RefPtr elementToFocus =
2701 aElement && aElement->IsInComposedDoc() &&
2702 aElement->GetComposedDoc() == aWindow->GetExtantDoc()
2703 ? FlushAndCheckIfFocusable(aElement, aFlags)
2704 : nullptr;
2705 if (elementToFocus && !mFocusedElement &&
2706 GetFocusedBrowsingContext() == aWindow->GetBrowsingContext()) {
2707 mFocusedElement = elementToFocus;
2708
2709 nsIContent* focusedNode = aWindow->GetFocusedElement();
2710 const bool sendFocusEvent = elementToFocus->IsInComposedDoc() &&
2711 !IsNonFocusableRoot(elementToFocus);
2712 const bool isRefocus = focusedNode && focusedNode == elementToFocus;
2713 const bool shouldShowFocusRing =
2714 sendFocusEvent &&
2715 ShouldMatchFocusVisible(aWindow, *elementToFocus, aFlags);
2716
2717 aWindow->SetFocusedElement(elementToFocus, focusMethod, false);
2718
2719 const RefPtr<nsPresContext> presContext = presShell->GetPresContext();
2720 if (sendFocusEvent) {
2721 NotifyFocusStateChange(elementToFocus, nullptr, aFlags,
2722 /* aGettingFocus = */ true, shouldShowFocusRing);
2723
2724 // If this is a remote browser, focus its widget and activate remote
2725 // content. Note that we might no longer be in the same document,
2726 // due to the events we fired above when aIsNewDocument.
2727 if (presShell->GetDocument() == elementToFocus->GetComposedDoc()) {
2728 ActivateRemoteFrameIfNeeded(*elementToFocus, aActionId);
2729 }
2730
2731 IMEStateManager::OnChangeFocus(presContext, elementToFocus,
2732 GetFocusMoveActionCause(aFlags));
2733
2734 // as long as this focus wasn't because a window was raised, update the
2735 // commands
2736 // XXXndeakin P2 someone could adjust the focus during the update
2737 if (!aWindowRaised) {
2738 aWindow->UpdateCommands(u"focus"_ns);
2739 }
2740
2741 // If the focused element changed, scroll it into view
2742 if (aFocusChanged) {
2743 ScrollIntoView(presShell, elementToFocus, aFlags);
2744 }
2745
2746 if (!focusInOtherContentProcess) {
2747 RefPtr<Document> composedDocument = elementToFocus->GetComposedDoc();
2748 RefPtr<Element> relatedTargetElement =
2749 aBlurredElementInfo ? aBlurredElementInfo->mElement.get() : nullptr;
2750 SendFocusOrBlurEvent(eFocus, presShell, composedDocument,
2751 elementToFocus, aWindowRaised, isRefocus,
2752 relatedTargetElement);
2753 }
2754 } else {
2755 // We should notify IMEStateManager of actual focused element even if it
2756 // won't get focus event because the other IMEStateManager users do not
2757 // want to depend on this check, but IMEStateManager wants to verify
2758 // passed focused element for avoidng to overrride nested calls.
2759 IMEStateManager::OnChangeFocus(presContext, elementToFocus,
2760 GetFocusMoveActionCause(aFlags));
2761 if (!aWindowRaised) {
2762 aWindow->UpdateCommands(u"focus"_ns);
2763 }
2764 if (aFocusChanged) {
2765 // If the focused element changed, scroll it into view
2766 ScrollIntoView(presShell, elementToFocus, aFlags);
2767 }
2768 }
2769 } else {
2770 if (!mFocusedElement && mFocusedWindow == aWindow) {
2771 // When there is no focused element, IMEStateManager needs to adjust IME
2772 // enabled state with the document.
2773 RefPtr<nsPresContext> presContext = presShell->GetPresContext();
2774 IMEStateManager::OnChangeFocus(presContext, nullptr,
2775 GetFocusMoveActionCause(aFlags));
2776 }
2777
2778 if (!aWindowRaised) {
2779 aWindow->UpdateCommands(u"focus"_ns);
2780 }
2781 }
2782
2783 // update the caret visibility and position to match the newly focused
2784 // element. However, don't update the position if this was a focus due to a
2785 // mouse click as the selection code would already have moved the caret as
2786 // needed. If this is a different document than was focused before, also
2787 // update the caret's visibility. If this is the same document, the caret
2788 // visibility should be the same as before so there is no need to update it.
2789 if (mFocusedElement == elementToFocus) {
2790 RefPtr<Element> focusedElement = mFocusedElement;
2791 UpdateCaret(aFocusChanged && !(aFlags & FLAG_BYMOUSE), aIsNewDocument,
2792 focusedElement);
2793 }
2794}
2795
2796class FocusBlurEvent : public Runnable {
2797 public:
2798 FocusBlurEvent(EventTarget* aTarget, EventMessage aEventMessage,
2799 nsPresContext* aContext, bool aWindowRaised, bool aIsRefocus,
2800 EventTarget* aRelatedTarget)
2801 : mozilla::Runnable("FocusBlurEvent"),
2802 mTarget(aTarget),
2803 mContext(aContext),
2804 mEventMessage(aEventMessage),
2805 mWindowRaised(aWindowRaised),
2806 mIsRefocus(aIsRefocus),
2807 mRelatedTarget(aRelatedTarget) {}
2808
2809 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230, bug 1535398)
2810 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODvirtual nsresult Run() override {
2811 InternalFocusEvent event(true, mEventMessage);
2812 event.mFlags.mBubbles = false;
2813 event.mFlags.mCancelable = false;
2814 event.mFromRaise = mWindowRaised;
2815 event.mIsRefocus = mIsRefocus;
2816 event.mRelatedTarget = mRelatedTarget;
2817 return EventDispatcher::Dispatch(mTarget, mContext, &event);
2818 }
2819
2820 const nsCOMPtr<EventTarget> mTarget;
2821 const RefPtr<nsPresContext> mContext;
2822 EventMessage mEventMessage;
2823 bool mWindowRaised;
2824 bool mIsRefocus;
2825 nsCOMPtr<EventTarget> mRelatedTarget;
2826};
2827
2828class FocusInOutEvent : public Runnable {
2829 public:
2830 FocusInOutEvent(EventTarget* aTarget, EventMessage aEventMessage,
2831 nsPresContext* aContext,
2832 nsPIDOMWindowOuter* aOriginalFocusedWindow,
2833 nsIContent* aOriginalFocusedContent,
2834 EventTarget* aRelatedTarget)
2835 : mozilla::Runnable("FocusInOutEvent"),
2836 mTarget(aTarget),
2837 mContext(aContext),
2838 mEventMessage(aEventMessage),
2839 mOriginalFocusedWindow(aOriginalFocusedWindow),
2840 mOriginalFocusedContent(aOriginalFocusedContent),
2841 mRelatedTarget(aRelatedTarget) {}
2842
2843 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1415230, bug 1535398)
2844 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODvirtual nsresult Run() override {
2845 nsCOMPtr<nsIContent> originalWindowFocus =
2846 mOriginalFocusedWindow ? mOriginalFocusedWindow->GetFocusedElement()
2847 : nullptr;
2848 // Blink does not check that focus is the same after blur, but WebKit does.
2849 // Opt to follow Blink's behavior (see bug 687787).
2850 if (mEventMessage == eFocusOut ||
2851 originalWindowFocus == mOriginalFocusedContent) {
2852 InternalFocusEvent event(true, mEventMessage);
2853 event.mFlags.mBubbles = true;
2854 event.mFlags.mCancelable = false;
2855 event.mRelatedTarget = mRelatedTarget;
2856 return EventDispatcher::Dispatch(mTarget, mContext, &event);
2857 }
2858 return NS_OK;
2859 }
2860
2861 const nsCOMPtr<EventTarget> mTarget;
2862 const RefPtr<nsPresContext> mContext;
2863 EventMessage mEventMessage;
2864 nsCOMPtr<nsPIDOMWindowOuter> mOriginalFocusedWindow;
2865 nsCOMPtr<nsIContent> mOriginalFocusedContent;
2866 nsCOMPtr<EventTarget> mRelatedTarget;
2867};
2868
2869static Document* GetDocumentHelper(EventTarget* aTarget) {
2870 if (!aTarget) {
2871 return nullptr;
2872 }
2873 if (const nsINode* node = nsINode::FromEventTarget(aTarget)) {
2874 return node->OwnerDoc();
2875 }
2876 nsPIDOMWindowInner* win = nsPIDOMWindowInner::FromEventTarget(aTarget);
2877 return win ? win->GetExtantDoc() : nullptr;
2878}
2879
2880void nsFocusManager::FireFocusInOrOutEvent(
2881 EventMessage aEventMessage, PresShell* aPresShell, EventTarget* aTarget,
2882 nsPIDOMWindowOuter* aCurrentFocusedWindow,
2883 nsIContent* aCurrentFocusedContent, EventTarget* aRelatedTarget) {
2884 NS_ASSERTION(aEventMessage == eFocusIn || aEventMessage == eFocusOut,do { if (!(aEventMessage == eFocusIn || aEventMessage == eFocusOut
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Wrong event type for FireFocusInOrOutEvent"
, "aEventMessage == eFocusIn || aEventMessage == eFocusOut", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 2885); MOZ_PretendNoReturn(); } } while (0)
2885 "Wrong event type for FireFocusInOrOutEvent")do { if (!(aEventMessage == eFocusIn || aEventMessage == eFocusOut
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Wrong event type for FireFocusInOrOutEvent"
, "aEventMessage == eFocusIn || aEventMessage == eFocusOut", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 2885); MOZ_PretendNoReturn(); } } while (0)
;
2886
2887 nsContentUtils::AddScriptRunner(new FocusInOutEvent(
2888 aTarget, aEventMessage, aPresShell->GetPresContext(),
2889 aCurrentFocusedWindow, aCurrentFocusedContent, aRelatedTarget));
2890}
2891
2892void nsFocusManager::SendFocusOrBlurEvent(EventMessage aEventMessage,
2893 PresShell* aPresShell,
2894 Document* aDocument,
2895 EventTarget* aTarget,
2896 bool aWindowRaised, bool aIsRefocus,
2897 EventTarget* aRelatedTarget) {
2898 NS_ASSERTION(aEventMessage == eFocus || aEventMessage == eBlur,do { if (!(aEventMessage == eFocus || aEventMessage == eBlur)
) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Wrong event type for SendFocusOrBlurEvent"
, "aEventMessage == eFocus || aEventMessage == eBlur", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 2899); MOZ_PretendNoReturn(); } } while (0)
2899 "Wrong event type for SendFocusOrBlurEvent")do { if (!(aEventMessage == eFocus || aEventMessage == eBlur)
) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Wrong event type for SendFocusOrBlurEvent"
, "aEventMessage == eFocus || aEventMessage == eBlur", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 2899); MOZ_PretendNoReturn(); } } while (0)
;
2900
2901 nsCOMPtr<Document> eventTargetDoc = GetDocumentHelper(aTarget);
2902 nsCOMPtr<Document> relatedTargetDoc = GetDocumentHelper(aRelatedTarget);
2903
2904 // set aRelatedTarget to null if it's not in the same document as aTarget
2905 if (eventTargetDoc != relatedTargetDoc) {
2906 aRelatedTarget = nullptr;
2907 }
2908
2909 if (aDocument && aDocument->EventHandlingSuppressed()) {
2910 // if this event was already queued, remove it and append it to the end
2911 mDelayedBlurFocusEvents.RemoveElementsBy([&](const auto& event) {
2912 return event.mEventMessage == aEventMessage &&
2913 event.mPresShell == aPresShell && event.mDocument == aDocument &&
2914 event.mTarget == aTarget && event.mRelatedTarget == aRelatedTarget;
2915 });
2916
2917 mDelayedBlurFocusEvents.EmplaceBack(aEventMessage, aPresShell, aDocument,
2918 aTarget, aRelatedTarget);
2919 return;
2920 }
2921
2922 // If mDelayedBlurFocusEvents queue is not empty, check if there are events
2923 // that belongs to this doc, if yes, fire them first.
2924 if (aDocument && !aDocument->EventHandlingSuppressed() &&
2925 mDelayedBlurFocusEvents.Length()) {
2926 FireDelayedEvents(aDocument);
2927 }
2928
2929 FireFocusOrBlurEvent(aEventMessage, aPresShell, aTarget, aWindowRaised,
2930 aIsRefocus, aRelatedTarget);
2931}
2932
2933void nsFocusManager::FireFocusOrBlurEvent(EventMessage aEventMessage,
2934 PresShell* aPresShell,
2935 EventTarget* aTarget,
2936 bool aWindowRaised, bool aIsRefocus,
2937 EventTarget* aRelatedTarget) {
2938 nsCOMPtr<nsPIDOMWindowOuter> currentWindow = mFocusedWindow;
2939 nsCOMPtr<nsPIDOMWindowInner> targetWindow = do_QueryInterface(aTarget);
2940 nsCOMPtr<Document> targetDocument = do_QueryInterface(aTarget);
2941 nsCOMPtr<nsIContent> currentFocusedContent =
2942 currentWindow ? currentWindow->GetFocusedElement() : nullptr;
2943
2944#ifdef ACCESSIBILITY1
2945 nsAccessibilityService* accService = GetAccService();
2946 if (accService) {
2947 if (aEventMessage == eFocus) {
2948 accService->NotifyOfDOMFocus(aTarget);
2949 } else {
2950 accService->NotifyOfDOMBlur(aTarget);
2951 }
2952 }
2953#endif
2954
2955 aPresShell->ScheduleContentRelevancyUpdate(
2956 ContentRelevancyReason::FocusInSubtree);
2957
2958 nsContentUtils::AddScriptRunner(
2959 new FocusBlurEvent(aTarget, aEventMessage, aPresShell->GetPresContext(),
2960 aWindowRaised, aIsRefocus, aRelatedTarget));
2961
2962 // Check that the target is not a window or document before firing
2963 // focusin/focusout. Other browsers do not fire focusin/focusout on window,
2964 // despite being required in the spec, so follow their behavior.
2965 //
2966 // As for document, we should not even fire focus/blur, but until then, we
2967 // need this check. targetDocument should be removed once bug 1228802 is
2968 // resolved.
2969 if (!targetWindow && !targetDocument) {
2970 EventMessage focusInOrOutMessage =
2971 aEventMessage == eFocus ? eFocusIn : eFocusOut;
2972 FireFocusInOrOutEvent(focusInOrOutMessage, aPresShell, aTarget,
2973 currentWindow, currentFocusedContent, aRelatedTarget);
2974 }
2975}
2976
2977void nsFocusManager::ScrollIntoView(PresShell* aPresShell, nsIContent* aContent,
2978 uint32_t aFlags) {
2979 if (aFlags & FLAG_NOSCROLL) {
2980 return;
2981 }
2982
2983 // If the noscroll flag isn't set, scroll the newly focused element into view.
2984 const ScrollAxis axis(WhereToScroll::Center, WhenToScroll::IfNotVisible);
2985 aPresShell->ScrollContentIntoView(aContent, axis, axis,
2986 ScrollFlags::ScrollOverflowHidden);
2987 // Scroll the input / textarea selection into view, unless focused with the
2988 // mouse, see bug 572649.
2989 if (aFlags & FLAG_BYMOUSE) {
2990 return;
2991 }
2992 // ScrollContentIntoView flushes layout, so no need to flush again here.
2993 if (nsTextControlFrame* tf = do_QueryFrame(aContent->GetPrimaryFrame())) {
2994 tf->ScrollSelectionIntoViewAsync(nsTextControlFrame::ScrollAncestors::Yes);
2995 }
2996}
2997
2998void nsFocusManager::RaiseWindow(nsPIDOMWindowOuter* aWindow,
2999 CallerType aCallerType, uint64_t aActionId) {
3000 // don't raise windows that are already raised or are in the process of
3001 // being lowered
3002
3003 if (!aWindow || aWindow == mWindowBeingLowered) {
3004 return;
3005 }
3006
3007 if (XRE_IsParentProcess()) {
3008 if (aWindow == mActiveWindow) {
3009 return;
3010 }
3011 } else {
3012 BrowsingContext* bc = aWindow->GetBrowsingContext();
3013 // TODO: Deeper OOP frame hierarchies are
3014 // https://bugzilla.mozilla.org/show_bug.cgi?id=1661227
3015 if (bc == GetActiveBrowsingContext()) {
3016 return;
3017 }
3018 if (bc == GetFocusedBrowsingContext()) {
3019 return;
3020 }
3021 }
3022
3023 if (sTestMode) {
3024 // In test mode, emulate raising the window. WindowRaised takes
3025 // care of lowering the present active window. This happens in
3026 // a separate runnable to avoid touching multiple windows in
3027 // the current runnable.
3028
3029 nsCOMPtr<nsPIDOMWindowOuter> window(aWindow);
3030 RefPtr<nsFocusManager> self(this);
3031 NS_DispatchToCurrentThread(NS_NewRunnableFunction(
3032 "nsFocusManager::RaiseWindow",
3033 // TODO: Convert this to MOZ_CAN_RUN_SCRIPT (bug 1770093)
3034 [self, window]() MOZ_CAN_RUN_SCRIPT_BOUNDARY -> void {
3035 self->WindowRaised(window, GenerateFocusActionId());
3036 }));
3037 return;
3038 }
3039
3040 if (XRE_IsContentProcess()) {
3041 BrowsingContext* bc = aWindow->GetBrowsingContext();
3042 if (!bc->IsTop()) {
3043 // Assume the raise below will succeed and run the raising synchronously
3044 // in this process to make the focus event that is observable in this
3045 // process fire in the right order relative to mouseup when we are here
3046 // thanks to a mousedown.
3047 WindowRaised(aWindow, aActionId);
3048 }
3049 }
3050
3051#if defined(XP_WIN)
3052 // Windows would rather we focus the child widget, otherwise, the toplevel
3053 // widget will always end up being focused. Fortunately, focusing the child
3054 // widget will also have the effect of raising the window this widget is in.
3055 // But on other platforms, we can just focus the toplevel widget to raise
3056 // the window.
3057 nsCOMPtr<nsPIDOMWindowOuter> childWindow;
3058 GetFocusedDescendant(aWindow, eIncludeAllDescendants,
3059 getter_AddRefs(childWindow));
3060 if (!childWindow) {
3061 childWindow = aWindow;
3062 }
3063
3064 nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
3065 if (!docShell) {
3066 return;
3067 }
3068
3069 PresShell* presShell = docShell->GetPresShell();
3070 if (!presShell) {
3071 return;
3072 }
3073
3074 if (nsViewManager* vm = presShell->GetViewManager()) {
3075 nsCOMPtr<nsIWidget> widget = vm->GetRootWidget();
3076 if (widget) {
3077 widget->SetFocus(nsIWidget::Raise::Yes, aCallerType);
3078 }
3079 }
3080#else
3081 nsCOMPtr<nsIBaseWindow> treeOwnerAsWin =
3082 do_QueryInterface(aWindow->GetDocShell());
3083 if (treeOwnerAsWin) {
3084 nsCOMPtr<nsIWidget> widget;
3085 treeOwnerAsWin->GetMainWidget(getter_AddRefs(widget));
3086 if (widget) {
3087 widget->SetFocus(nsIWidget::Raise::Yes, aCallerType);
3088 }
3089 }
3090#endif
3091}
3092
3093void nsFocusManager::UpdateCaretForCaretBrowsingMode() {
3094 RefPtr<Element> focusedElement = mFocusedElement;
3095 UpdateCaret(false, true, focusedElement);
3096}
3097
3098void nsFocusManager::UpdateCaret(bool aMoveCaretToFocus, bool aUpdateVisibility,
3099 nsIContent* aContent) {
3100 LOGFOCUS(("Update Caret: %d %d", aMoveCaretToFocus, aUpdateVisibility))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Update Caret: %d %d"
, aMoveCaretToFocus, aUpdateVisibility); } } while (0)
;
3101
3102 if (!mFocusedWindow) {
3103 return;
3104 }
3105
3106 // this is called when a document is focused or when the caretbrowsing
3107 // preference is changed
3108 nsCOMPtr<nsIDocShell> focusedDocShell = mFocusedWindow->GetDocShell();
3109 if (!focusedDocShell) {
3110 return;
3111 }
3112
3113 if (focusedDocShell->ItemType() == nsIDocShellTreeItem::typeChrome) {
3114 return; // Never browse with caret in chrome
3115 }
3116
3117 bool browseWithCaret = Preferences::GetBool("accessibility.browsewithcaret");
3118
3119 const RefPtr<PresShell> presShell = focusedDocShell->GetPresShell();
3120 if (!presShell) {
3121 return;
3122 }
3123
3124 // If this is an editable document which isn't contentEditable, or a
3125 // contentEditable document and the node to focus is contentEditable,
3126 // return, so that we don't mess with caret visibility.
3127 bool isEditable = false;
3128 focusedDocShell->GetEditable(&isEditable);
3129
3130 if (isEditable) {
3131 Document* doc = presShell->GetDocument();
3132
3133 bool isContentEditableDoc =
3134 doc &&
3135 doc->GetEditingState() == Document::EditingState::eContentEditable;
3136
3137 bool isFocusEditable = aContent && aContent->HasFlag(NODE_IS_EDITABLE);
3138 if (!isContentEditableDoc || isFocusEditable) {
3139 return;
3140 }
3141 }
3142
3143 if (!isEditable && aMoveCaretToFocus) {
3144 MoveCaretToFocus(presShell, aContent);
3145 }
3146
3147 // The above MoveCaretToFocus call may run scripts which
3148 // may clear mFocusWindow
3149 if (!mFocusedWindow) {
3150 return;
3151 }
3152
3153 if (!aUpdateVisibility) {
3154 return;
3155 }
3156
3157 // XXXndeakin this doesn't seem right. It should be checking for this only
3158 // on the nearest ancestor frame which is a chrome frame. But this is
3159 // what the existing code does, so just leave it for now.
3160 if (!browseWithCaret) {
3161 nsCOMPtr<Element> docElement = mFocusedWindow->GetFrameElementInternal();
3162 if (docElement)
3163 browseWithCaret = docElement->AttrValueIs(
3164 kNameSpaceID_None, nsGkAtoms::showcaret, u"true"_ns, eCaseMatters);
3165 }
3166
3167 SetCaretVisible(presShell, browseWithCaret, aContent);
3168}
3169
3170void nsFocusManager::MoveCaretToFocus(PresShell* aPresShell,
3171 nsIContent* aContent) {
3172 nsCOMPtr<Document> doc = aPresShell->GetDocument();
3173 if (doc) {
3174 RefPtr<nsFrameSelection> frameSelection = aPresShell->FrameSelection();
3175 RefPtr<Selection> domSelection =
3176 frameSelection->GetSelection(SelectionType::eNormal);
3177 if (domSelection) {
3178 // First clear the selection. This way, if there is no currently focused
3179 // content, the selection will just be cleared.
3180 domSelection->RemoveAllRanges(IgnoreErrors());
3181 if (aContent) {
3182 ErrorResult rv;
3183 RefPtr<nsRange> newRange = doc->CreateRange(rv);
3184 if (NS_WARN_IF(rv.Failed())NS_warn_if_impl(rv.Failed(), "rv.Failed()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 3184)
) {
3185 rv.SuppressException();
3186 return;
3187 }
3188
3189 // Set the range to the start of the currently focused node
3190 // Make sure it's collapsed
3191 newRange->SelectNodeContents(*aContent, IgnoreErrors());
3192
3193 if (!aContent->GetFirstChild() ||
3194 aContent->IsHTMLFormControlElement()) {
3195 // If current focus node is a leaf, set range to before the
3196 // node by using the parent as a container.
3197 // This prevents it from appearing as selected.
3198 newRange->SetStartBefore(*aContent, IgnoreErrors());
3199 newRange->SetEndBefore(*aContent, IgnoreErrors());
3200 }
3201 domSelection->AddRangeAndSelectFramesAndNotifyListeners(*newRange,
3202 IgnoreErrors());
3203 domSelection->CollapseToStart(IgnoreErrors());
3204 }
3205 }
3206 }
3207}
3208
3209nsresult nsFocusManager::SetCaretVisible(PresShell* aPresShell, bool aVisible,
3210 nsIContent* aContent) {
3211 // When browsing with caret, make sure caret is visible after new focus
3212 // Return early if there is no caret. This can happen for the testcase
3213 // for bug 308025 where a window is closed in a blur handler.
3214 RefPtr<nsCaret> caret = aPresShell->GetCaret();
3215 if (!caret) {
3216 return NS_OK;
3217 }
3218
3219 bool caretVisible = caret->IsVisible();
3220 if (!aVisible && !caretVisible) {
3221 return NS_OK;
3222 }
3223
3224 RefPtr<nsFrameSelection> frameSelection;
3225 if (aContent) {
3226 NS_ASSERTION(aContent->GetComposedDoc() == aPresShell->GetDocument(),do { if (!(aContent->GetComposedDoc() == aPresShell->GetDocument
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Wrong document?", "aContent->GetComposedDoc() == aPresShell->GetDocument()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 3227); MOZ_PretendNoReturn(); } } while (0)
3227 "Wrong document?")do { if (!(aContent->GetComposedDoc() == aPresShell->GetDocument
())) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Wrong document?", "aContent->GetComposedDoc() == aPresShell->GetDocument()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 3227); MOZ_PretendNoReturn(); } } while (0)
;
3228 nsIFrame* focusFrame = aContent->GetPrimaryFrame();
3229 if (focusFrame) {
3230 frameSelection = focusFrame->GetFrameSelection();
3231 }
3232 }
3233
3234 RefPtr<nsFrameSelection> docFrameSelection = aPresShell->FrameSelection();
3235
3236 if (docFrameSelection && caret &&
3237 (frameSelection == docFrameSelection || !aContent)) {
3238 Selection* domSelection =
3239 docFrameSelection->GetSelection(SelectionType::eNormal);
3240 if (domSelection) {
3241 // First, hide the caret to prevent attempting to show it in
3242 // SetCaretDOMSelection
3243 aPresShell->SetCaretEnabled(false);
3244
3245 // Caret must blink on non-editable elements
3246 caret->SetIgnoreUserModify(true);
3247 // Tell the caret which selection to use
3248 caret->SetSelection(domSelection);
3249
3250 // In content, we need to set the caret. The only special case is edit
3251 // fields, which have a different frame selection from the document.
3252 // They will take care of making the caret visible themselves.
3253
3254 aPresShell->SetCaretReadOnly(false);
3255 aPresShell->SetCaretEnabled(aVisible);
3256 }
3257 }
3258
3259 return NS_OK;
3260}
3261
3262void nsFocusManager::GetSelectionLocation(Document* aDocument,
3263 PresShell* aPresShell,
3264 nsIContent** aStartContent,
3265 nsIContent** aEndContent) {
3266 *aStartContent = *aEndContent = nullptr;
3267
3268 nsPresContext* presContext = aPresShell->GetPresContext();
3269 NS_ASSERTION(presContext, "mPresContent is null!!")do { if (!(presContext)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "mPresContent is null!!"
, "presContext", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 3269); MOZ_PretendNoReturn(); } } while (0)
;
3270
3271 RefPtr<Selection> domSelection =
3272 aPresShell->ConstFrameSelection()->GetSelection(SelectionType::eNormal);
3273 if (!domSelection) {
3274 return;
3275 }
3276
3277 const nsRange* domRange = domSelection->GetRangeAt(0);
3278 if (!domRange || !domRange->IsPositioned()) {
3279 return;
3280 }
3281 nsIContent* start = nsIContent::FromNode(domRange->GetStartContainer());
3282 nsIContent* end = nsIContent::FromNode(domRange->GetEndContainer());
3283 if (nsIContent* child = domRange->StartRef().GetChildAtOffset()) {
3284 start = child;
3285 }
3286 if (nsIContent* child = domRange->EndRef().GetChildAtOffset()) {
3287 end = child;
3288 }
3289
3290 // Next check to see if our caret is at the very end of a text node. If so,
3291 // the caret is actually sitting in front of the next logical frame's primary
3292 // node - so for this case we need to change the content to that node.
3293 // Note that if the text does not have text frame, we do not need to retreive
3294 // caret frame. This could occur if text frame has only collapsisble white-
3295 // spaces and is around a block boundary or an ancestor of it is invisible.
3296 // XXX If there is a visible text sibling, should we return it in the former
3297 // case?
3298 if (auto* text = Text::FromNodeOrNull(start);
3299 text && text->GetPrimaryFrame() &&
3300 text->TextDataLength() == domRange->StartOffset() &&
3301 domSelection->IsCollapsed()) {
3302 nsIFrame* startFrame = start->GetPrimaryFrame();
3303 // Yes, indeed we were at the end of the last node
3304 nsIFrame* limiter =
3305 domSelection && domSelection->GetAncestorLimiter()
3306 ? domSelection->GetAncestorLimiter()->GetPrimaryFrame()
3307 : nullptr;
3308 nsFrameIterator frameIterator(presContext, startFrame,
3309 nsFrameIterator::Type::Leaf,
3310 false, // aVisual
3311 false, // aLockInScrollView
3312 true, // aFollowOOFs
3313 false, // aSkipPopupChecks
3314 limiter);
3315
3316 nsIFrame* newCaretFrame = nullptr;
3317 nsIContent* newCaretContent = start;
3318 const bool endOfSelectionInStartNode = start == end;
3319 do {
3320 // Continue getting the next frame until the primary content for the
3321 // frame we are on changes - we don't want to be stuck in the same
3322 // place
3323 frameIterator.Next();
3324 newCaretFrame = frameIterator.CurrentItem();
3325 if (!newCaretFrame) {
3326 break;
3327 }
3328 newCaretContent = newCaretFrame->GetContent();
3329 } while (!newCaretContent || newCaretContent == start);
3330
3331 if (newCaretFrame && newCaretContent) {
3332 // If the caret is exactly at the same position of the new frame,
3333 // then we can use the newCaretFrame and newCaretContent for our
3334 // position
3335 nsRect caretRect;
3336 if (nsIFrame* frame = nsCaret::GetGeometry(domSelection, &caretRect)) {
3337 nsPoint caretWidgetOffset;
3338 nsIWidget* widget = frame->GetNearestWidget(caretWidgetOffset);
3339 caretRect.MoveBy(caretWidgetOffset);
3340 nsPoint newCaretOffset;
3341 nsIWidget* newCaretWidget =
3342 newCaretFrame->GetNearestWidget(newCaretOffset);
3343 if (widget == newCaretWidget && caretRect.TopLeft() == newCaretOffset) {
3344 // The caret is at the start of the new element.
3345 startFrame = newCaretFrame;
Value stored to 'startFrame' is never read
3346 start = newCaretContent;
3347 if (endOfSelectionInStartNode) {
3348 end = newCaretContent; // Ensure end of selection is
3349 // not before start
3350 }
3351 }
3352 }
3353 }
3354 }
3355
3356 NS_IF_ADDREF(*aStartContent = start)ns_if_addref(*aStartContent = start);
3357 NS_IF_ADDREF(*aEndContent = end)ns_if_addref(*aEndContent = end);
3358}
3359
3360nsresult nsFocusManager::DetermineElementToMoveFocus(
3361 nsPIDOMWindowOuter* aWindow, nsIContent* aStartContent, int32_t aType,
3362 bool aNoParentTraversal, bool aNavigateByKey, nsIContent** aNextContent) {
3363 *aNextContent = nullptr;
3364
3365 // This is used for document navigation only. It will be set to true if we
3366 // start navigating from a starting point. If this starting point is near the
3367 // end of the document (for example, an element on a statusbar), and there
3368 // are no child documents or panels before the end of the document, then we
3369 // will need to ensure that we don't consider the root chrome window when we
3370 // loop around and instead find the next child document/panel, as focus is
3371 // already in that window. This flag will be cleared once we navigate into
3372 // another document.
3373 bool mayFocusRoot = (aStartContent != nullptr);
3374
3375 nsCOMPtr<nsIContent> startContent = aStartContent;
3376 if (!startContent && aType != MOVEFOCUS_CARET) {
3377 if (aType == MOVEFOCUS_FORWARDDOC || aType == MOVEFOCUS_BACKWARDDOC) {
3378 // When moving between documents, make sure to get the right
3379 // starting content in a descendant.
3380 nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
3381 startContent = GetFocusedDescendant(aWindow, eIncludeAllDescendants,
3382 getter_AddRefs(focusedWindow));
3383 } else if (aType != MOVEFOCUS_LASTDOC) {
3384 // Otherwise, start at the focused node. If MOVEFOCUS_LASTDOC is used,
3385 // then we are document-navigating backwards from chrome to the content
3386 // process, and we don't want to use this so that we start from the end
3387 // of the document.
3388 startContent = aWindow->GetFocusedElement();
3389 }
3390 }
3391
3392 nsCOMPtr<Document> doc;
3393 if (startContent)
3394 doc = startContent->GetComposedDoc();
3395 else
3396 doc = aWindow->GetExtantDoc();
3397 if (!doc) return NS_OK;
3398
3399 // True if we are navigating by document (F6/Shift+F6) or false if we are
3400 // navigating by element (Tab/Shift+Tab).
3401 const bool forDocumentNavigation =
3402 aType == MOVEFOCUS_FORWARDDOC || aType == MOVEFOCUS_BACKWARDDOC ||
3403 aType == MOVEFOCUS_FIRSTDOC || aType == MOVEFOCUS_LASTDOC;
3404
3405 // If moving to the root or first document, find the root element and return.
3406 if (aType == MOVEFOCUS_ROOT || aType == MOVEFOCUS_FIRSTDOC) {
3407 NS_IF_ADDREF(*aNextContent = GetRootForFocus(aWindow, doc, false, false))ns_if_addref(*aNextContent = GetRootForFocus(aWindow, doc, false
, false))
;
3408 if (!*aNextContent && aType == MOVEFOCUS_FIRSTDOC) {
3409 // When looking for the first document, if the root wasn't focusable,
3410 // find the next focusable document.
3411 aType = MOVEFOCUS_FORWARDDOC;
3412 } else {
3413 return NS_OK;
3414 }
3415 }
3416
3417 // rootElement and presShell may be set to sub-document's ones so that they
3418 // cannot be `const`.
3419 RefPtr<Element> rootElement = doc->GetRootElement();
3420 NS_ENSURE_TRUE(rootElement, NS_OK)do { if ((__builtin_expect(!!(!(rootElement)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "rootElement" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 3420); return NS_OK; } } while (false)
;
3421
3422 RefPtr<PresShell> presShell = doc->GetPresShell();
3423 NS_ENSURE_TRUE(presShell, NS_OK)do { if ((__builtin_expect(!!(!(presShell)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "presShell" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 3423); return NS_OK; } } while (false)
;
3424
3425 if (aType == MOVEFOCUS_FIRST) {
3426 if (!aStartContent) {
3427 startContent = rootElement;
3428 }
3429 return GetNextTabbableContent(presShell, startContent, nullptr,
3430 startContent, true, 1, false, false,
3431 aNavigateByKey, false, false, aNextContent);
3432 }
3433 if (aType == MOVEFOCUS_LAST) {
3434 if (!aStartContent) {
3435 startContent = rootElement;
3436 }
3437 return GetNextTabbableContent(presShell, startContent, nullptr,
3438 startContent, false, 0, false, false,
3439 aNavigateByKey, false, false, aNextContent);
3440 }
3441
3442 bool forward = (aType == MOVEFOCUS_FORWARD || aType == MOVEFOCUS_FORWARDDOC ||
3443 aType == MOVEFOCUS_CARET);
3444 bool doNavigation = true;
3445 bool ignoreTabIndex = false;
3446 // when a popup is open, we want to ensure that tab navigation occurs only
3447 // within the most recently opened panel. If a popup is open, its frame will
3448 // be stored in popupFrame.
3449 nsIFrame* popupFrame = nullptr;
3450
3451 int32_t tabIndex = forward ? 1 : 0;
3452 if (startContent) {
3453 nsIFrame* frame = startContent->GetPrimaryFrame();
3454 tabIndex = (frame && !startContent->IsHTMLElement(nsGkAtoms::area))
3455 ? frame->IsFocusable().mTabIndex
3456 : startContent->IsFocusableWithoutStyle().mTabIndex;
3457
3458 // if the current element isn't tabbable, ignore the tabindex and just
3459 // look for the next element. The root content won't have a tabindex
3460 // so just treat this as the beginning of the tab order.
3461 if (tabIndex < 0) {
3462 tabIndex = 1;
3463 if (startContent != rootElement) {
3464 ignoreTabIndex = true;
3465 }
3466 }
3467
3468 // check if the focus is currently inside a popup. Elements such as the
3469 // autocomplete widget use the noautofocus attribute to allow the focus to
3470 // remain outside the popup when it is opened.
3471 if (frame) {
3472 popupFrame = nsLayoutUtils::GetClosestFrameOfType(
3473 frame, LayoutFrameType::MenuPopup);
3474 }
3475
3476 if (popupFrame && !forDocumentNavigation) {
3477 // Don't navigate outside of a popup, so pretend that the
3478 // root content is the popup itself
3479 rootElement = popupFrame->GetContent()->AsElement();
3480 NS_ASSERTION(rootElement, "Popup frame doesn't have a content node")do { if (!(rootElement)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Popup frame doesn't have a content node"
, "rootElement", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 3480); MOZ_PretendNoReturn(); } } while (0)
;
3481 } else if (!forward) {
3482 // If focus moves backward and when current focused node is root
3483 // content or <body> element which is editable by contenteditable
3484 // attribute, focus should move to its parent document.
3485 if (startContent == rootElement) {
3486 doNavigation = false;
3487 } else {
3488 Document* doc = startContent->GetComposedDoc();
3489 if (startContent ==
3490 nsLayoutUtils::GetEditableRootContentByContentEditable(doc)) {
3491 doNavigation = false;
3492 }
3493 }
3494 }
3495 } else {
3496 if (aType != MOVEFOCUS_CARET) {
3497 // if there is no focus, yet a panel is open, focus the first item in
3498 // the panel
3499 nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
3500 if (pm) {
3501 popupFrame = pm->GetTopPopup(PopupType::Panel);
3502 }
3503 }
3504 if (popupFrame) {
3505 // When there is a popup open, and no starting content, start the search
3506 // at the topmost popup.
3507 startContent = popupFrame->GetContent();
3508 NS_ASSERTION(startContent, "Popup frame doesn't have a content node")do { if (!(startContent)) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"Popup frame doesn't have a content node", "startContent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 3508); MOZ_PretendNoReturn(); } } while (0)
;
3509 // Unless we are searching for documents, set the root content to the
3510 // popup as well, so that we don't tab-navigate outside the popup.
3511 // When navigating by documents, we start at the popup but can navigate
3512 // outside of it to look for other panels and documents.
3513 if (!forDocumentNavigation) {
3514 rootElement = startContent->AsElement();
3515 }
3516
3517 doc = startContent ? startContent->GetComposedDoc() : nullptr;
3518 } else {
3519 // Otherwise, for content shells, start from the location of the caret.
3520 nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
3521 if (docShell && docShell->ItemType() != nsIDocShellTreeItem::typeChrome) {
3522 nsCOMPtr<nsIContent> endSelectionContent;
3523 GetSelectionLocation(doc, presShell, getter_AddRefs(startContent),
3524 getter_AddRefs(endSelectionContent));
3525 // If the selection is on the rootElement, then there is no selection
3526 if (startContent == rootElement) {
3527 startContent = nullptr;
3528 }
3529
3530 if (aType == MOVEFOCUS_CARET) {
3531 // GetFocusInSelection finds a focusable link near the caret.
3532 // If there is no start content though, don't do this to avoid
3533 // focusing something unexpected.
3534 if (startContent) {
3535 GetFocusInSelection(aWindow, startContent, endSelectionContent,
3536 aNextContent);
3537 }
3538 return NS_OK;
3539 }
3540
3541 if (startContent) {
3542 // when starting from a selection, we always want to find the next or
3543 // previous element in the document. So the tabindex on elements
3544 // should be ignored.
3545 ignoreTabIndex = true;
3546 // If selection starts from a focusable and tabbable element, we want
3547 // to make it focused rather than next/previous one.
3548 if (startContent->IsElement() && startContent->GetPrimaryFrame() &&
3549 startContent->GetPrimaryFrame()->IsFocusable().IsTabbable()) {
3550 startContent =
3551 forward ? (startContent->GetPreviousSibling()
3552 ? startContent->GetPreviousSibling()
3553 // We don't need to get previous leaf node
3554 // because it may be too far from
3555 // startContent. We just want the previous
3556 // node immediately before startContent.
3557 : startContent->GetParent())
3558 // We want the next node immdiately after startContent.
3559 // Therefore, we don't want its first child.
3560 : startContent->GetNextNonChildNode();
3561 // If we reached the root element, we should treat it as there is no
3562 // selection as same as above.
3563 if (startContent == rootElement) {
3564 startContent = nullptr;
3565 }
3566 }
3567 }
3568 }
3569
3570 if (!startContent) {
3571 // otherwise, just use the root content as the starting point
3572 startContent = rootElement;
3573 NS_ENSURE_TRUE(startContent, NS_OK)do { if ((__builtin_expect(!!(!(startContent)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "startContent" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 3573); return NS_OK; } } while (false)
;
3574 }
3575 }
3576 }
3577
3578 // Check if the starting content is the same as the content assigned to the
3579 // retargetdocumentfocus attribute. Is so, we don't want to start searching
3580 // from there but instead from the beginning of the document. Otherwise, the
3581 // content that appears before the retargetdocumentfocus element will never
3582 // get checked as it will be skipped when the focus is retargetted to it.
3583 if (forDocumentNavigation && nsContentUtils::IsChromeDoc(doc)) {
3584 nsAutoString retarget;
3585
3586 if (rootElement->GetAttr(nsGkAtoms::retargetdocumentfocus, retarget)) {
3587 nsIContent* retargetElement = doc->GetElementById(retarget);
3588 // The common case here is the urlbar where focus is on the anonymous
3589 // input inside the textbox, but the retargetdocumentfocus attribute
3590 // refers to the textbox. The Contains check will return false and the
3591 // IsInclusiveDescendantOf check will return true in this case.
3592 if (retargetElement &&
3593 (retargetElement == startContent ||
3594 (!retargetElement->Contains(startContent) &&
3595 startContent->IsInclusiveDescendantOf(retargetElement)))) {
3596 startContent = rootElement;
3597 }
3598 }
3599 }
3600
3601 NS_ASSERTION(startContent, "starting content not set")do { if (!(startContent)) { NS_DebugBreak(NS_DEBUG_ASSERTION,
"starting content not set", "startContent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 3601); MOZ_PretendNoReturn(); } } while (0)
;
3602
3603 // keep a reference to the starting content. If we find that again, it means
3604 // we've iterated around completely and we don't want to adjust the focus.
3605 // The skipOriginalContentCheck will be set to true only for the first time
3606 // GetNextTabbableContent is called. This ensures that we don't break out
3607 // when nothing is focused to start with. Specifically,
3608 // GetNextTabbableContent first checks the root content -- which happens to
3609 // be the same as the start content -- when nothing is focused and tabbing
3610 // forward. Without skipOriginalContentCheck set to true, we'd end up
3611 // returning right away and focusing nothing. Luckily, GetNextTabbableContent
3612 // will never wrap around on its own, and can only return the original
3613 // content when it is called a second time or later.
3614 bool skipOriginalContentCheck = true;
3615 const nsCOMPtr<nsIContent> originalStartContent = startContent;
3616
3617 LOGCONTENTNAVIGATION("Focus Navigation Start Content %s", startContent.get())if ((__builtin_expect(!!(mozilla::detail::log_test(gFocusNavigationLog
, LogLevel::Debug)), 0))) { nsAutoCString tag("(none)"_ns); if
(startContent.get()) { startContent.get()->NodeInfo()->
NameAtom()->ToUTF8String(tag); } do { const ::mozilla::LogModule
* moz_real_module = gFocusNavigationLog; if ((__builtin_expect
(!!(mozilla::detail::log_test(moz_real_module, LogLevel::Debug
)), 0))) { mozilla::detail::log_print(moz_real_module, LogLevel
::Debug, "Focus Navigation Start Content %s", tag.get()); } }
while (0); }
;
3618 LOGFOCUSNAVIGATION((" Forward: %d Tabindex: %d Ignore: %d DocNav: %d",do { const ::mozilla::LogModule* moz_real_module = gFocusNavigationLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Forward: %d Tabindex: %d Ignore: %d DocNav: %d"
, forward, tabIndex, ignoreTabIndex, forDocumentNavigation); }
} while (0)
3619 forward, tabIndex, ignoreTabIndex,do { const ::mozilla::LogModule* moz_real_module = gFocusNavigationLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Forward: %d Tabindex: %d Ignore: %d DocNav: %d"
, forward, tabIndex, ignoreTabIndex, forDocumentNavigation); }
} while (0)
3620 forDocumentNavigation))do { const ::mozilla::LogModule* moz_real_module = gFocusNavigationLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Forward: %d Tabindex: %d Ignore: %d DocNav: %d"
, forward, tabIndex, ignoreTabIndex, forDocumentNavigation); }
} while (0)
;
3621
3622 while (doc) {
3623 if (doNavigation) {
3624 nsCOMPtr<nsIContent> nextFocus;
3625 // TODO: MOZ_KnownLive is reruired due to bug 1770680
3626 nsresult rv = GetNextTabbableContent(
3627 presShell, rootElement,
3628 MOZ_KnownLive(skipOriginalContentCheck ? nullptr(skipOriginalContentCheck ? nullptr : originalStartContent.get
())
3629 : originalStartContent.get())(skipOriginalContentCheck ? nullptr : originalStartContent.get
())
,
3630 startContent, forward, tabIndex, ignoreTabIndex,
3631 forDocumentNavigation, aNavigateByKey, false, false,
3632 getter_AddRefs(nextFocus));
3633 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 3633); return rv; } } while (false)
;
3634 if (rv == NS_SUCCESS_DOM_NO_OPERATION) {
3635 // Navigation was redirected to a child process, so just return.
3636 return NS_OK;
3637 }
3638
3639 // found a content node to focus.
3640 if (nextFocus) {
3641 LOGCONTENTNAVIGATION("Next Content: %s", nextFocus.get())if ((__builtin_expect(!!(mozilla::detail::log_test(gFocusNavigationLog
, LogLevel::Debug)), 0))) { nsAutoCString tag("(none)"_ns); if
(nextFocus.get()) { nextFocus.get()->NodeInfo()->NameAtom
()->ToUTF8String(tag); } do { const ::mozilla::LogModule* moz_real_module
= gFocusNavigationLog; if ((__builtin_expect(!!(mozilla::detail
::log_test(moz_real_module, LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Debug, "Next Content: %s"
, tag.get()); } } while (0); }
;
3642
3643 // as long as the found node was not the same as the starting node,
3644 // set it as the return value. For document navigation, we can return
3645 // the same element in case there is only one content node that could
3646 // be returned, for example, in a child process document.
3647 if (nextFocus != originalStartContent || forDocumentNavigation) {
3648 nextFocus.forget(aNextContent);
3649 }
3650 return NS_OK;
3651 }
3652
3653 if (popupFrame && !forDocumentNavigation) {
3654 // in a popup, so start again from the beginning of the popup. However,
3655 // if we already started at the beginning, then there isn't anything to
3656 // focus, so just return
3657 if (startContent != rootElement) {
3658 startContent = rootElement;
3659 tabIndex = forward ? 1 : 0;
3660 continue;
3661 }
3662 return NS_OK;
3663 }
3664 }
3665
3666 doNavigation = true;
3667 skipOriginalContentCheck = forDocumentNavigation;
3668 ignoreTabIndex = false;
3669
3670 if (aNoParentTraversal) {
3671 if (startContent == rootElement) {
3672 return NS_OK;
3673 }
3674
3675 startContent = rootElement;
3676 tabIndex = forward ? 1 : 0;
3677 continue;
3678 }
3679
3680 // Reached the beginning or end of the document. Next, navigate up to the
3681 // parent document and try again.
3682 nsCOMPtr<nsPIDOMWindowOuter> piWindow = doc->GetWindow();
3683 NS_ENSURE_TRUE(piWindow, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(piWindow)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "piWindow" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 3683); return NS_ERROR_FAILURE; } } while (false)
;
3684
3685 nsCOMPtr<nsIDocShell> docShell = piWindow->GetDocShell();
3686 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(docShell)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "docShell" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 3686); return NS_ERROR_FAILURE; } } while (false)
;
3687
3688 // Get the frame element this window is inside and, from that, get the
3689 // parent document and presshell. If there is no enclosing frame element,
3690 // then this is a top-level, embedded or remote window.
3691 startContent = piWindow->GetFrameElementInternal();
3692 if (startContent) {
3693 doc = startContent->GetComposedDoc();
3694 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(doc)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "doc" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 3694); return NS_ERROR_FAILURE; } } while (false)
;
3695
3696 rootElement = doc->GetRootElement();
3697 presShell = doc->GetPresShell();
3698
3699 // We can focus the root element now that we have moved to another
3700 // document.
3701 mayFocusRoot = true;
3702
3703 nsIFrame* frame = startContent->GetPrimaryFrame();
3704 if (!frame) {
3705 return NS_OK;
3706 }
3707
3708 tabIndex = frame->IsFocusable().mTabIndex;
3709 if (tabIndex < 0) {
3710 tabIndex = 1;
3711 ignoreTabIndex = true;
3712 }
3713
3714 // if the frame is inside a popup, make sure to scan only within the
3715 // popup. This handles the situation of tabbing amongst elements
3716 // inside an iframe which is itself inside a popup. Otherwise,
3717 // navigation would move outside the popup when tabbing outside the
3718 // iframe.
3719 if (!forDocumentNavigation) {
3720 popupFrame = nsLayoutUtils::GetClosestFrameOfType(
3721 frame, LayoutFrameType::MenuPopup);
3722 if (popupFrame) {
3723 rootElement = popupFrame->GetContent()->AsElement();
3724 NS_ASSERTION(rootElement, "Popup frame doesn't have a content node")do { if (!(rootElement)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Popup frame doesn't have a content node"
, "rootElement", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 3724); MOZ_PretendNoReturn(); } } while (0)
;
3725 }
3726 }
3727 } else {
3728 if (aNavigateByKey) {
3729 // There is no parent, so move the focus to the parent process.
3730 if (auto* child = BrowserChild::GetFrom(docShell)) {
3731 child->SendMoveFocus(forward, forDocumentNavigation);
3732 // Blur the current element.
3733 RefPtr<BrowsingContext> focusedBC = GetFocusedBrowsingContext();
3734 if (focusedBC && focusedBC->IsInProcess()) {
3735 Blur(focusedBC, nullptr, true, true, false,
3736 GenerateFocusActionId());
3737 } else {
3738 nsCOMPtr<nsPIDOMWindowOuter> window = docShell->GetWindow();
3739 window->SetFocusedElement(nullptr);
3740 }
3741 return NS_OK;
3742 }
3743 }
3744
3745 // If we have reached the end of the top-level document, focus the
3746 // first element in the top-level document. This should always happen
3747 // when navigating by document forwards but when navigating backwards,
3748 // only do this if we started in another document or within a popup frame.
3749 // If the focus started in this window outside a popup however, we should
3750 // continue by looping around to the end again.
3751 if (forDocumentNavigation && (forward || mayFocusRoot || popupFrame)) {
3752 // HTML content documents can have their root element focused by
3753 // pressing F6(a focus ring appears around the entire content area
3754 // frame). This root appears in the tab order before all of the elements
3755 // in the document. Chrome documents however cannot be focused directly,
3756 // so instead we focus the first focusable element within the window.
3757 // For example, the urlbar.
3758 RefPtr<Element> rootElementForFocus =
3759 GetRootForFocus(piWindow, doc, true, true);
3760 return FocusFirst(rootElementForFocus, aNextContent,
3761 true /* aReachedToEndForDocumentNavigation */);
3762 }
3763
3764 // Once we have hit the top-level and have iterated to the end again, we
3765 // just want to break out next time we hit this spot to prevent infinite
3766 // iteration.
3767 mayFocusRoot = true;
3768
3769 // reset the tab index and start again from the beginning or end
3770 startContent = rootElement;
3771 tabIndex = forward ? 1 : 0;
3772 }
3773
3774 // wrapped all the way around and didn't find anything to move the focus
3775 // to, so just break out
3776 if (startContent == originalStartContent) {
3777 break;
3778 }
3779 }
3780
3781 return NS_OK;
3782}
3783
3784uint32_t nsFocusManager::ProgrammaticFocusFlags(const FocusOptions& aOptions) {
3785 uint32_t flags = FLAG_BYJS;
3786 if (aOptions.mPreventScroll) {
3787 flags |= FLAG_NOSCROLL;
3788 }
3789 if (aOptions.mFocusVisible.WasPassed()) {
3790 flags |= aOptions.mFocusVisible.Value() ? FLAG_SHOWRING : FLAG_NOSHOWRING;
3791 }
3792 if (UserActivation::IsHandlingKeyboardInput()) {
3793 flags |= FLAG_BYKEY;
3794 }
3795 // TODO: We could do a similar thing if we're handling mouse input, but that
3796 // changes focusability of some elements so may be more risky.
3797 return flags;
3798}
3799
3800static bool IsHostOrSlot(const nsIContent* aContent) {
3801 return aContent && (aContent->GetShadowRoot() ||
3802 aContent->IsHTMLElement(nsGkAtoms::slot));
3803}
3804
3805// Helper class to iterate contents in scope by traversing flattened tree
3806// in tree order
3807class MOZ_STACK_CLASS ScopedContentTraversal {
3808 public:
3809 ScopedContentTraversal(nsIContent* aStartContent, nsIContent* aOwner)
3810 : mCurrent(aStartContent), mOwner(aOwner) {
3811 MOZ_ASSERT(aStartContent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStartContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aStartContent))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("aStartContent",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 3811); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStartContent"
")"); do { *((volatile int*)__null) = 3811; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3812 }
3813
3814 void Next();
3815 void Prev();
3816
3817 void Reset() { SetCurrent(mOwner); }
3818
3819 nsIContent* GetCurrent() const { return mCurrent; }
3820
3821 private:
3822 void SetCurrent(nsIContent* aContent) { mCurrent = aContent; }
3823
3824 nsIContent* mCurrent;
3825 nsIContent* mOwner;
3826};
3827
3828void ScopedContentTraversal::Next() {
3829 MOZ_ASSERT(mCurrent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCurrent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mCurrent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mCurrent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 3829); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCurrent" ")"
); do { *((volatile int*)__null) = 3829; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3830
3831 // Get mCurrent's first child if it's in the same scope.
3832 if (!IsHostOrSlot(mCurrent) || mCurrent == mOwner) {
3833 StyleChildrenIterator iter(mCurrent);
3834 nsIContent* child = iter.GetNextChild();
3835 if (child) {
3836 SetCurrent(child);
3837 return;
3838 }
3839 }
3840
3841 // If mOwner has no children, END traversal
3842 if (mCurrent == mOwner) {
3843 SetCurrent(nullptr);
3844 return;
3845 }
3846
3847 nsIContent* current = mCurrent;
3848 while (1) {
3849 // Create parent's iterator and move to current
3850 nsIContent* parent = current->GetFlattenedTreeParent();
3851 StyleChildrenIterator parentIter(parent);
3852 parentIter.Seek(current);
3853
3854 // Get next sibling of current
3855 if (nsIContent* next = parentIter.GetNextChild()) {
3856 SetCurrent(next);
3857 return;
3858 }
3859
3860 // If no next sibling and parent is mOwner, END traversal
3861 if (parent == mOwner) {
3862 SetCurrent(nullptr);
3863 return;
3864 }
3865
3866 current = parent;
3867 }
3868}
3869
3870void ScopedContentTraversal::Prev() {
3871 MOZ_ASSERT(mCurrent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCurrent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mCurrent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mCurrent", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 3871); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCurrent" ")"
); do { *((volatile int*)__null) = 3871; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3872
3873 nsIContent* parent;
3874 nsIContent* last;
3875 if (mCurrent == mOwner) {
3876 // Get last child of mOwner
3877 StyleChildrenIterator ownerIter(mOwner, false /* aStartAtBeginning */);
3878 last = ownerIter.GetPreviousChild();
3879
3880 parent = last;
3881 } else {
3882 // Create parent's iterator and move to mCurrent
3883 parent = mCurrent->GetFlattenedTreeParent();
3884 StyleChildrenIterator parentIter(parent);
3885 parentIter.Seek(mCurrent);
3886
3887 // Get previous sibling
3888 last = parentIter.GetPreviousChild();
3889 }
3890
3891 while (last) {
3892 parent = last;
3893 if (IsHostOrSlot(parent)) {
3894 // Skip contents in other scopes
3895 break;
3896 }
3897
3898 // Find last child
3899 StyleChildrenIterator iter(parent, false /* aStartAtBeginning */);
3900 last = iter.GetPreviousChild();
3901 }
3902
3903 // If parent is mOwner and no previous sibling remains, END traversal
3904 SetCurrent(parent == mOwner ? nullptr : parent);
3905}
3906
3907static bool IsOpenPopoverWithInvoker(nsIContent* aContent) {
3908 if (auto* popover = Element::FromNode(aContent)) {
3909 return popover && popover->IsPopoverOpen() &&
3910 popover->GetPopoverData()->GetInvoker();
3911 }
3912 return false;
3913}
3914
3915static nsIContent* InvokerForPopoverShowingState(nsIContent* aContent) {
3916 Element* invoker = Element::FromNode(aContent);
3917 if (!invoker) {
3918 return nullptr;
3919 }
3920
3921 nsGenericHTMLElement* popover = invoker->GetEffectivePopoverTargetElement();
3922 if (popover && popover->IsPopoverOpen() &&
3923 popover->GetPopoverData()->GetInvoker() == invoker) {
3924 return aContent;
3925 }
3926
3927 return nullptr;
3928}
3929
3930/**
3931 * Returns scope owner of aContent.
3932 * A scope owner is either a shadow host, or slot.
3933 */
3934static nsIContent* FindScopeOwner(nsIContent* aContent) {
3935 nsIContent* currentContent = aContent;
3936 while (currentContent) {
3937 nsIContent* parent = currentContent->GetFlattenedTreeParent();
3938
3939 // Shadow host / Slot
3940 if (IsHostOrSlot(parent)) {
3941 return parent;
3942 }
3943
3944 currentContent = parent;
3945 }
3946
3947 return nullptr;
3948}
3949
3950/**
3951 * Host and Slot elements need to be handled as if they had tabindex 0 even
3952 * when they don't have the attribute. This is a helper method to get the
3953 * right value for focus navigation. If aIsFocusable is passed, it is set to
3954 * true if the element itself is focusable.
3955 */
3956static int32_t HostOrSlotTabIndexValue(const nsIContent* aContent,
3957 bool* aIsFocusable = nullptr) {
3958 MOZ_ASSERT(IsHostOrSlot(aContent))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsHostOrSlot(aContent))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsHostOrSlot(aContent)))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("IsHostOrSlot(aContent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 3958); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsHostOrSlot(aContent)"
")"); do { *((volatile int*)__null) = 3958; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3959
3960 if (aIsFocusable) {
3961 nsIFrame* frame = aContent->GetPrimaryFrame();
3962 *aIsFocusable = frame && frame->IsFocusable().mTabIndex >= 0;
3963 }
3964
3965 const nsAttrValue* attrVal =
3966 aContent->AsElement()->GetParsedAttr(nsGkAtoms::tabindex);
3967 if (!attrVal) {
3968 return 0;
3969 }
3970
3971 if (attrVal->Type() == nsAttrValue::eInteger) {
3972 return attrVal->GetIntegerValue();
3973 }
3974
3975 return -1;
3976}
3977
3978nsIContent* nsFocusManager::GetNextTabbableContentInScope(
3979 nsIContent* aOwner, nsIContent* aStartContent,
3980 nsIContent* aOriginalStartContent, bool aForward, int32_t aCurrentTabIndex,
3981 bool aIgnoreTabIndex, bool aForDocumentNavigation, bool aNavigateByKey,
3982 bool aSkipOwner, bool aReachedToEndForDocumentNavigation) {
3983 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsHostOrSlot(aOwner) || IsOpenPopoverWithInvoker(aOwner
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(IsHostOrSlot(aOwner) || IsOpenPopoverWithInvoker(aOwner
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("IsHostOrSlot(aOwner) || IsOpenPopoverWithInvoker(aOwner)" " ("
"Scope owner should be host, slot or an open popover with invoker set."
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 3985); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsHostOrSlot(aOwner) || IsOpenPopoverWithInvoker(aOwner)"
") (" "Scope owner should be host, slot or an open popover with invoker set."
")"); do { *((volatile int*)__null) = 3985; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3984 IsHostOrSlot(aOwner) || IsOpenPopoverWithInvoker(aOwner),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsHostOrSlot(aOwner) || IsOpenPopoverWithInvoker(aOwner
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(IsHostOrSlot(aOwner) || IsOpenPopoverWithInvoker(aOwner
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("IsHostOrSlot(aOwner) || IsOpenPopoverWithInvoker(aOwner)" " ("
"Scope owner should be host, slot or an open popover with invoker set."
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 3985); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsHostOrSlot(aOwner) || IsOpenPopoverWithInvoker(aOwner)"
") (" "Scope owner should be host, slot or an open popover with invoker set."
")"); do { *((volatile int*)__null) = 3985; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
3985 "Scope owner should be host, slot or an open popover with invoker set.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsHostOrSlot(aOwner) || IsOpenPopoverWithInvoker(aOwner
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(IsHostOrSlot(aOwner) || IsOpenPopoverWithInvoker(aOwner
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("IsHostOrSlot(aOwner) || IsOpenPopoverWithInvoker(aOwner)" " ("
"Scope owner should be host, slot or an open popover with invoker set."
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 3985); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsHostOrSlot(aOwner) || IsOpenPopoverWithInvoker(aOwner)"
") (" "Scope owner should be host, slot or an open popover with invoker set."
")"); do { *((volatile int*)__null) = 3985; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3986
3987 // XXX: Why don't we ignore tabindex when the current tabindex < 0?
3988 MOZ_ASSERT_IF(aCurrentTabIndex < 0, aIgnoreTabIndex)do { if (aCurrentTabIndex < 0) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(aIgnoreTabIndex)
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aIgnoreTabIndex))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("aIgnoreTabIndex", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 3988); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aIgnoreTabIndex"
")"); do { *((volatile int*)__null) = 3988; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
3989
3990 if (!aSkipOwner && (aForward && aOwner == aStartContent)) {
3991 if (nsIFrame* frame = aOwner->GetPrimaryFrame()) {
3992 auto focusable = frame->IsFocusable();
3993 if (focusable && focusable.mTabIndex >= 0) {
3994 return aOwner;
3995 }
3996 }
3997 }
3998
3999 //
4000 // Iterate contents in scope
4001 //
4002 ScopedContentTraversal contentTraversal(aStartContent, aOwner);
4003 nsCOMPtr<nsIContent> iterContent;
4004 nsIContent* firstNonChromeOnly =
4005 aStartContent->IsInNativeAnonymousSubtree()
4006 ? aStartContent->FindFirstNonChromeOnlyAccessContent()
4007 : nullptr;
4008 while (1) {
4009 // Iterate tab index to find corresponding contents in scope
4010
4011 while (1) {
4012 // Iterate remaining contents in scope to find next content to focus
4013
4014 // Get next content
4015 aForward ? contentTraversal.Next() : contentTraversal.Prev();
4016 iterContent = contentTraversal.GetCurrent();
4017
4018 if (firstNonChromeOnly && firstNonChromeOnly == iterContent) {
4019 // We just broke out from the native anonymous content, so move
4020 // to the previous/next node of the native anonymous owner.
4021 if (aForward) {
4022 contentTraversal.Next();
4023 } else {
4024 contentTraversal.Prev();
4025 }
4026 iterContent = contentTraversal.GetCurrent();
4027 }
4028 if (!iterContent) {
4029 // Reach the end
4030 break;
4031 }
4032
4033 int32_t tabIndex = 0;
4034 if (iterContent->IsInNativeAnonymousSubtree() &&
4035 iterContent->GetPrimaryFrame()) {
4036 tabIndex = iterContent->GetPrimaryFrame()->IsFocusable().mTabIndex;
4037 } else if (IsHostOrSlot(iterContent)) {
4038 tabIndex = HostOrSlotTabIndexValue(iterContent);
4039 } else {
4040 nsIFrame* frame = iterContent->GetPrimaryFrame();
4041 if (!frame) {
4042 continue;
4043 }
4044 tabIndex = frame->IsFocusable().mTabIndex;
4045 }
4046 if (tabIndex < 0 || !(aIgnoreTabIndex || tabIndex == aCurrentTabIndex)) {
4047 continue;
4048 }
4049
4050 if (!IsHostOrSlot(iterContent)) {
4051 nsCOMPtr<nsIContent> elementInFrame;
4052 bool checkSubDocument = true;
4053 if (aForDocumentNavigation &&
4054 TryDocumentNavigation(iterContent, &checkSubDocument,
4055 getter_AddRefs(elementInFrame))) {
4056 return elementInFrame;
4057 }
4058 if (!checkSubDocument) {
4059 if (aReachedToEndForDocumentNavigation &&
4060 StaticPrefs::dom_disable_tab_focus_to_root_element() &&
4061 nsContentUtils::IsChromeDoc(iterContent->GetComposedDoc())) {
4062 // aReachedToEndForDocumentNavigation is true means
4063 // 1. This is a document navigation (i.e, VK_F6, Control + Tab)
4064 // 2. This is the top-level document (Note that we may start from
4065 // a subdocument)
4066 // 3. We've searched through the this top-level document already
4067 if (!GetRootForChildDocument(iterContent)) {
4068 // We'd like to focus the first focusable element of this
4069 // top-level chrome document.
4070 return iterContent;
4071 }
4072 }
4073 continue;
4074 }
4075
4076 if (TryToMoveFocusToSubDocument(iterContent, aOriginalStartContent,
4077 aForward, aForDocumentNavigation,
4078 aNavigateByKey,
4079 aReachedToEndForDocumentNavigation,
4080 getter_AddRefs(elementInFrame))) {
4081 return elementInFrame;
4082 }
4083
4084 // Found content to focus
4085 return iterContent;
4086 }
4087
4088 // Search in scope owned by iterContent
4089 nsIContent* contentToFocus = GetNextTabbableContentInScope(
4090 iterContent, iterContent, aOriginalStartContent, aForward,
4091 aForward ? 1 : 0, aIgnoreTabIndex, aForDocumentNavigation,
4092 aNavigateByKey, false /* aSkipOwner */,
4093 aReachedToEndForDocumentNavigation);
4094 if (contentToFocus) {
4095 return contentToFocus;
4096 }
4097 };
4098
4099 // If already at lowest priority tab (0), end search completely.
4100 // A bit counterintuitive but true, tabindex order goes 1, 2, ... 32767, 0
4101 if (aCurrentTabIndex == (aForward ? 0 : 1)) {
4102 break;
4103 }
4104
4105 // We've been just trying to find some focusable element, and haven't, so
4106 // bail out.
4107 if (aIgnoreTabIndex) {
4108 break;
4109 }
4110
4111 // Continue looking for next highest priority tabindex
4112 aCurrentTabIndex = GetNextTabIndex(aOwner, aCurrentTabIndex, aForward);
4113 contentTraversal.Reset();
4114 }
4115
4116 // Return scope owner at last for backward navigation if its tabindex
4117 // is non-negative
4118 if (!aSkipOwner && !aForward) {
4119 if (nsIFrame* frame = aOwner->GetPrimaryFrame()) {
4120 auto focusable = frame->IsFocusable();
4121 if (focusable && focusable.mTabIndex >= 0) {
4122 return aOwner;
4123 }
4124 }
4125 }
4126
4127 return nullptr;
4128}
4129
4130nsIContent* nsFocusManager::GetNextTabbableContentInAncestorScopes(
4131 nsIContent* aStartOwner, nsCOMPtr<nsIContent>& aStartContent /* inout */,
4132 nsIContent* aOriginalStartContent, bool aForward, int32_t* aCurrentTabIndex,
4133 bool* aIgnoreTabIndex, bool aForDocumentNavigation, bool aNavigateByKey,
4134 bool aReachedToEndForDocumentNavigation) {
4135 MOZ_ASSERT(aStartOwner == FindScopeOwner(aStartContent),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStartOwner == FindScopeOwner(aStartContent))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aStartOwner == FindScopeOwner(aStartContent)))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aStartOwner == FindScopeOwner(aStartContent)"
" (" "aStartOWner should be the scope owner of aStartContent"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 4136); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStartOwner == FindScopeOwner(aStartContent)"
") (" "aStartOWner should be the scope owner of aStartContent"
")"); do { *((volatile int*)__null) = 4136; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4136 "aStartOWner should be the scope owner of aStartContent")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aStartOwner == FindScopeOwner(aStartContent))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(aStartOwner == FindScopeOwner(aStartContent)))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("aStartOwner == FindScopeOwner(aStartContent)"
" (" "aStartOWner should be the scope owner of aStartContent"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 4136); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aStartOwner == FindScopeOwner(aStartContent)"
") (" "aStartOWner should be the scope owner of aStartContent"
")"); do { *((volatile int*)__null) = 4136; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4137 MOZ_ASSERT(IsHostOrSlot(aStartOwner), "scope owner should be host or slot")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsHostOrSlot(aStartOwner))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsHostOrSlot(aStartOwner))))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("IsHostOrSlot(aStartOwner)"
" (" "scope owner should be host or slot" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 4137); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsHostOrSlot(aStartOwner)"
") (" "scope owner should be host or slot" ")"); do { *((volatile
int*)__null) = 4137; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
4138
4139 nsCOMPtr<nsIContent> owner = aStartOwner;
4140 nsCOMPtr<nsIContent> startContent = aStartContent;
4141 while (IsHostOrSlot(owner)) {
4142 int32_t tabIndex = 0;
4143 if (IsHostOrSlot(startContent)) {
4144 tabIndex = HostOrSlotTabIndexValue(startContent);
4145 } else if (nsIFrame* frame = startContent->GetPrimaryFrame()) {
4146 tabIndex = frame->IsFocusable().mTabIndex;
4147 } else {
4148 tabIndex = startContent->IsFocusableWithoutStyle().mTabIndex;
4149 }
4150 nsIContent* contentToFocus = GetNextTabbableContentInScope(
4151 owner, startContent, aOriginalStartContent, aForward, tabIndex,
4152 tabIndex < 0, aForDocumentNavigation, aNavigateByKey,
4153 false /* aSkipOwner */, aReachedToEndForDocumentNavigation);
4154 if (contentToFocus) {
4155 return contentToFocus;
4156 }
4157
4158 startContent = owner;
4159 owner = FindScopeOwner(startContent);
4160 }
4161
4162 // If not found in shadow DOM, search from the top level shadow host in light
4163 // DOM
4164 aStartContent = startContent;
4165 *aCurrentTabIndex = HostOrSlotTabIndexValue(startContent);
4166
4167 if (*aCurrentTabIndex < 0) {
4168 *aIgnoreTabIndex = true;
4169 }
4170
4171 return nullptr;
4172}
4173
4174static nsIContent* GetTopLevelScopeOwner(nsIContent* aContent) {
4175 nsIContent* topLevelScopeOwner = nullptr;
4176 while (aContent) {
4177 if (HTMLSlotElement* slot = aContent->GetAssignedSlot()) {
4178 aContent = slot;
4179 topLevelScopeOwner = aContent;
4180 } else if (ShadowRoot* shadowRoot = aContent->GetContainingShadow()) {
4181 aContent = shadowRoot->Host();
4182 topLevelScopeOwner = aContent;
4183 } else {
4184 aContent = aContent->GetParent();
4185 if (aContent && (HTMLSlotElement::FromNode(aContent) ||
4186 IsOpenPopoverWithInvoker(aContent))) {
4187 topLevelScopeOwner = aContent;
4188 }
4189 }
4190 }
4191
4192 return topLevelScopeOwner;
4193}
4194
4195nsresult nsFocusManager::GetNextTabbableContent(
4196 PresShell* aPresShell, nsIContent* aRootContent,
4197 nsIContent* aOriginalStartContent, nsIContent* aStartContent, bool aForward,
4198 int32_t aCurrentTabIndex, bool aIgnoreTabIndex, bool aForDocumentNavigation,
4199 bool aNavigateByKey, bool aSkipPopover,
4200 bool aReachedToEndForDocumentNavigation, nsIContent** aResultContent) {
4201 *aResultContent = nullptr;
4202
4203 if (!aStartContent) {
4204 return NS_OK;
4205 }
4206
4207 nsCOMPtr<nsIContent> startContent = aStartContent;
4208 nsCOMPtr<nsIContent> currentTopLevelScopeOwner =
4209 GetTopLevelScopeOwner(startContent);
4210
4211 LOGCONTENTNAVIGATION("GetNextTabbable: %s", startContent)if ((__builtin_expect(!!(mozilla::detail::log_test(gFocusNavigationLog
, LogLevel::Debug)), 0))) { nsAutoCString tag("(none)"_ns); if
(startContent) { startContent->NodeInfo()->NameAtom()->
ToUTF8String(tag); } do { const ::mozilla::LogModule* moz_real_module
= gFocusNavigationLog; if ((__builtin_expect(!!(mozilla::detail
::log_test(moz_real_module, LogLevel::Debug)), 0))) { mozilla
::detail::log_print(moz_real_module, LogLevel::Debug, "GetNextTabbable: %s"
, tag.get()); } } while (0); }
;
4212 LOGFOCUSNAVIGATION((" tabindex: %d", aCurrentTabIndex))do { const ::mozilla::LogModule* moz_real_module = gFocusNavigationLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " tabindex: %d",
aCurrentTabIndex); } } while (0)
;
4213
4214 // If startContent is a shadow host or slot in forward navigation,
4215 // search in scope owned by startContent
4216 if (aForward && IsHostOrSlot(startContent)) {
4217 nsIContent* contentToFocus = GetNextTabbableContentInScope(
4218 startContent, startContent, aOriginalStartContent, aForward, 1,
4219 aIgnoreTabIndex, aForDocumentNavigation, aNavigateByKey,
4220 true /* aSkipOwner */, aReachedToEndForDocumentNavigation);
4221 if (contentToFocus) {
4222 NS_ADDREF(*aResultContent = contentToFocus)(*aResultContent = contentToFocus)->AddRef();
4223 return NS_OK;
4224 }
4225 }
4226
4227 // If startContent is a popover invoker, search the popover scope.
4228 if (!aSkipPopover) {
4229 if (InvokerForPopoverShowingState(startContent)) {
4230 if (aForward) {
4231 RefPtr<nsIContent> popover =
4232 startContent->GetEffectivePopoverTargetElement();
4233 nsIContent* contentToFocus = GetNextTabbableContentInScope(
4234 popover, popover, aOriginalStartContent, aForward, 1,
4235 aIgnoreTabIndex, aForDocumentNavigation, aNavigateByKey,
4236 true /* aSkipOwner */, aReachedToEndForDocumentNavigation);
4237 if (contentToFocus) {
4238 NS_ADDREF(*aResultContent = contentToFocus)(*aResultContent = contentToFocus)->AddRef();
4239 return NS_OK;
4240 }
4241 }
4242 }
4243 }
4244
4245 // If startContent is in a scope owned by Shadow DOM search from scope
4246 // including startContent
4247 if (nsCOMPtr<nsIContent> owner = FindScopeOwner(startContent)) {
4248 nsIContent* contentToFocus = GetNextTabbableContentInAncestorScopes(
4249 owner, startContent /* inout */, aOriginalStartContent, aForward,
4250 &aCurrentTabIndex, &aIgnoreTabIndex, aForDocumentNavigation,
4251 aNavigateByKey, aReachedToEndForDocumentNavigation);
4252 if (contentToFocus) {
4253 NS_ADDREF(*aResultContent = contentToFocus)(*aResultContent = contentToFocus)->AddRef();
4254 return NS_OK;
4255 }
4256 }
4257
4258 // If we reach here, it means no next tabbable content in shadow DOM.
4259 // We need to continue searching in light DOM, starting at the top level
4260 // shadow host in light DOM (updated startContent) and its tabindex
4261 // (updated aCurrentTabIndex).
4262 MOZ_ASSERT(!FindScopeOwner(startContent),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!FindScopeOwner(startContent))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!FindScopeOwner(startContent
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!FindScopeOwner(startContent)" " (" "startContent should not be owned by Shadow DOM at this point"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 4263); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!FindScopeOwner(startContent)"
") (" "startContent should not be owned by Shadow DOM at this point"
")"); do { *((volatile int*)__null) = 4263; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4263 "startContent should not be owned by Shadow DOM at this point")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!FindScopeOwner(startContent))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!FindScopeOwner(startContent
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!FindScopeOwner(startContent)" " (" "startContent should not be owned by Shadow DOM at this point"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 4263); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!FindScopeOwner(startContent)"
") (" "startContent should not be owned by Shadow DOM at this point"
")"); do { *((volatile int*)__null) = 4263; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4264
4265 nsPresContext* presContext = aPresShell->GetPresContext();
4266
4267 bool getNextFrame = true;
4268 nsCOMPtr<nsIContent> iterStartContent = startContent;
4269 nsIContent* topLevelScopeStartContent = startContent;
4270 // Iterate tab index to find corresponding contents
4271 while (1) {
4272 nsIFrame* frame = iterStartContent->GetPrimaryFrame();
4273 // if there is no frame, look for another content node that has a frame
4274 while (!frame) {
4275 // if the root content doesn't have a frame, just return
4276 if (iterStartContent == aRootContent) {
4277 return NS_OK;
4278 }
4279
4280 // look for the next or previous content node in tree order
4281 iterStartContent = aForward ? iterStartContent->GetNextNode()
4282 : iterStartContent->GetPrevNode();
4283 if (!iterStartContent) {
4284 break;
4285 }
4286
4287 frame = iterStartContent->GetPrimaryFrame();
4288 // Host without frame, enter its scope.
4289 if (!frame && iterStartContent->GetShadowRoot()) {
4290 int32_t tabIndex = HostOrSlotTabIndexValue(iterStartContent);
4291 if (tabIndex >= 0 &&
4292 (aIgnoreTabIndex || aCurrentTabIndex == tabIndex)) {
4293 nsIContent* contentToFocus = GetNextTabbableContentInScope(
4294 iterStartContent, iterStartContent, aOriginalStartContent,
4295 aForward, aForward ? 1 : 0, aIgnoreTabIndex,
4296 aForDocumentNavigation, aNavigateByKey, true /* aSkipOwner */,
4297 aReachedToEndForDocumentNavigation);
4298 if (contentToFocus) {
4299 NS_ADDREF(*aResultContent = contentToFocus)(*aResultContent = contentToFocus)->AddRef();
4300 return NS_OK;
4301 }
4302 }
4303 }
4304 // we've already skipped over the initial focused content, so we
4305 // don't want to traverse frames.
4306 getNextFrame = false;
4307 }
4308
4309 Maybe<nsFrameIterator> frameIterator;
4310 if (frame) {
4311 // For tab navigation, pass false for aSkipPopupChecks so that we don't
4312 // iterate into or out of a popup. For document naviation pass true to
4313 // ignore these boundaries.
4314 frameIterator.emplace(presContext, frame, nsFrameIterator::Type::PreOrder,
4315 false, // aVisual
4316 false, // aLockInScrollView
4317 true, // aFollowOOFs
4318 aForDocumentNavigation // aSkipPopupChecks
4319 );
4320 MOZ_ASSERT(frameIterator)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(frameIterator)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(frameIterator))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("frameIterator",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 4320); AnnotateMozCrashReason("MOZ_ASSERT" "(" "frameIterator"
")"); do { *((volatile int*)__null) = 4320; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4321
4322 if (iterStartContent == aRootContent) {
4323 if (!aForward) {
4324 frameIterator->Last();
4325 } else if (aRootContent->IsFocusableWithoutStyle()) {
4326 frameIterator->Next();
4327 }
4328 frame = frameIterator->CurrentItem();
4329 } else if (getNextFrame &&
4330 (!iterStartContent ||
4331 !iterStartContent->IsHTMLElement(nsGkAtoms::area))) {
4332 // Need to do special check in case we're in an imagemap which has
4333 // multiple content nodes per frame, so don't skip over the starting
4334 // frame.
4335 frame = frameIterator->Traverse(aForward);
4336 }
4337 }
4338
4339 nsIContent* oldTopLevelScopeOwner = nullptr;
4340 // Walk frames to find something tabbable matching aCurrentTabIndex
4341 while (frame) {
4342 // Try to find the topmost scope owner, since we want to skip the node
4343 // that is not owned by document in frame traversal.
4344 const nsCOMPtr<nsIContent> currentContent = frame->GetContent();
4345 if (currentTopLevelScopeOwner) {
4346 oldTopLevelScopeOwner = currentTopLevelScopeOwner;
4347 }
4348 currentTopLevelScopeOwner = GetTopLevelScopeOwner(currentContent);
4349
4350 // We handle popover case separately.
4351 if (currentTopLevelScopeOwner &&
4352 currentTopLevelScopeOwner == oldTopLevelScopeOwner &&
4353 !IsOpenPopoverWithInvoker(currentTopLevelScopeOwner)) {
4354 // We're within non-document scope, continue.
4355 do {
4356 if (aForward) {
4357 frameIterator->Next();
4358 } else {
4359 frameIterator->Prev();
4360 }
4361 frame = frameIterator->CurrentItem();
4362 // For the usage of GetPrevContinuation, see the comment
4363 // at the end of while (frame) loop.
4364 } while (frame && frame->GetPrevContinuation());
4365 continue;
4366 }
4367
4368 // Stepping out popover scope.
4369 // For forward, search for the next tabbable content after invoker.
4370 // For backward, we should get back to the invoker if the invoker is
4371 // focusable. Otherwise search for the next tabbable content after
4372 // invoker.
4373 if (oldTopLevelScopeOwner &&
4374 IsOpenPopoverWithInvoker(oldTopLevelScopeOwner) &&
4375 currentTopLevelScopeOwner != oldTopLevelScopeOwner) {
4376 if (auto* popover = Element::FromNode(oldTopLevelScopeOwner)) {
4377 RefPtr<nsIContent> invokerContent =
4378 popover->GetPopoverData()->GetInvoker()->AsContent();
4379 RefPtr<nsIContent> rootElement = invokerContent;
4380 if (auto* doc = invokerContent->GetComposedDoc()) {
4381 rootElement = doc->GetRootElement();
4382 }
4383 if (aForward) {
4384 nsIFrame* frame = invokerContent->GetPrimaryFrame();
4385 int32_t tabIndex = frame->IsFocusable().mTabIndex;
4386 if (tabIndex >= 0 &&
4387 (aIgnoreTabIndex || aCurrentTabIndex == tabIndex)) {
4388 nsresult rv = GetNextTabbableContent(
4389 aPresShell, rootElement, nullptr, invokerContent, true,
4390 tabIndex, false, false, aNavigateByKey, true,
4391 aReachedToEndForDocumentNavigation, aResultContent);
4392 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && *aResultContent) {
4393 return rv;
4394 }
4395 }
4396 } else if (invokerContent) {
4397 nsIFrame* frame = invokerContent->GetPrimaryFrame();
4398 if (frame && frame->IsFocusable()) {
4399 invokerContent.forget(aResultContent);
4400 return NS_OK;
4401 }
4402 nsresult rv = GetNextTabbableContent(
4403 aPresShell, rootElement, aOriginalStartContent, invokerContent,
4404 false, 0, true, false, aNavigateByKey, true,
4405 aReachedToEndForDocumentNavigation, aResultContent);
4406 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && *aResultContent) {
4407 return rv;
4408 }
4409 }
4410 }
4411 }
4412
4413 if (!aForward) {
4414 if (InvokerForPopoverShowingState(currentContent)) {
4415 RefPtr<nsIContent> popover =
4416 currentContent->GetEffectivePopoverTargetElement();
4417 nsIContent* contentToFocus = GetNextTabbableContentInScope(
4418 popover, popover, aOriginalStartContent, aForward, 0,
4419 aIgnoreTabIndex, aForDocumentNavigation, aNavigateByKey,
4420 true /* aSkipOwner */, aReachedToEndForDocumentNavigation);
4421
4422 if (contentToFocus) {
4423 NS_ADDREF(*aResultContent = contentToFocus)(*aResultContent = contentToFocus)->AddRef();
4424 return NS_OK;
4425 }
4426 }
4427 }
4428 // For document navigation, check if this element is an open panel. Since
4429 // panels aren't focusable (tabIndex would be -1), we'll just assume that
4430 // for document navigation, the tabIndex is 0.
4431 if (aForDocumentNavigation && currentContent && (aCurrentTabIndex == 0) &&
4432 currentContent->IsXULElement(nsGkAtoms::panel)) {
4433 nsMenuPopupFrame* popupFrame = do_QueryFrame(frame);
4434 // Check if the panel is open. Closed panels are ignored since you can't
4435 // focus anything in them.
4436 if (popupFrame && popupFrame->IsOpen()) {
4437 // When moving backward, skip the popup we started in otherwise it
4438 // will be selected again.
4439 bool validPopup = true;
4440 if (!aForward) {
4441 nsIContent* content = topLevelScopeStartContent;
4442 while (content) {
4443 if (content == currentContent) {
4444 validPopup = false;
4445 break;
4446 }
4447
4448 content = content->GetParent();
4449 }
4450 }
4451
4452 if (validPopup) {
4453 // Since a panel isn't focusable itself, find the first focusable
4454 // content within the popup. If there isn't any focusable content
4455 // in the popup, skip this popup and continue iterating through the
4456 // frames. We pass the panel itself (currentContent) as the starting
4457 // and root content, so that we only find content within the panel.
4458 // Note also that we pass false for aForDocumentNavigation since we
4459 // want to locate the first content, not the first document.
4460 nsresult rv = GetNextTabbableContent(
4461 aPresShell, currentContent, nullptr, currentContent, true, 1,
4462 false, false, aNavigateByKey, false,
4463 aReachedToEndForDocumentNavigation, aResultContent);
4464 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && *aResultContent) {
4465 return rv;
4466 }
4467 }
4468 }
4469 }
4470
4471 // As of now, 2018/04/12, sequential focus navigation is still
4472 // in the obsolete Shadow DOM specification.
4473 // http://w3c.github.io/webcomponents/spec/shadow/#sequential-focus-navigation
4474 // "if ELEMENT is focusable, a shadow host, or a slot element,
4475 // append ELEMENT to NAVIGATION-ORDER."
4476 // and later in "For each element ELEMENT in NAVIGATION-ORDER: "
4477 // hosts and slots are handled before other elements.
4478 if (currentTopLevelScopeOwner &&
4479 !IsOpenPopoverWithInvoker(currentTopLevelScopeOwner)) {
4480 bool focusableHostSlot;
4481 int32_t tabIndex = HostOrSlotTabIndexValue(currentTopLevelScopeOwner,
4482 &focusableHostSlot);
4483 // Host or slot itself isn't focusable or going backwards, enter its
4484 // scope.
4485 if ((!aForward || !focusableHostSlot) && tabIndex >= 0 &&
4486 (aIgnoreTabIndex || aCurrentTabIndex == tabIndex)) {
4487 nsIContent* contentToFocus = GetNextTabbableContentInScope(
4488 currentTopLevelScopeOwner, currentTopLevelScopeOwner,
4489 aOriginalStartContent, aForward, aForward ? 1 : 0,
4490 aIgnoreTabIndex, aForDocumentNavigation, aNavigateByKey,
4491 true /* aSkipOwner */, aReachedToEndForDocumentNavigation);
4492 if (contentToFocus) {
4493 NS_ADDREF(*aResultContent = contentToFocus)(*aResultContent = contentToFocus)->AddRef();
4494 return NS_OK;
4495 }
4496 // If we've wrapped around already, then carry on.
4497 if (aOriginalStartContent &&
4498 currentTopLevelScopeOwner ==
4499 GetTopLevelScopeOwner(aOriginalStartContent)) {
4500 // FIXME: Shouldn't this return null instead? aOriginalStartContent
4501 // isn't focusable after all.
4502 NS_ADDREF(*aResultContent = aOriginalStartContent)(*aResultContent = aOriginalStartContent)->AddRef();
4503 return NS_OK;
4504 }
4505 }
4506 // There is no next tabbable content in currentTopLevelScopeOwner's
4507 // scope. We should continue the loop in order to skip all contents that
4508 // is in currentTopLevelScopeOwner's scope.
4509 continue;
4510 }
4511
4512 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!GetTopLevelScopeOwner(currentContent) || IsOpenPopoverWithInvoker
(GetTopLevelScopeOwner(currentContent)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!GetTopLevelScopeOwner(currentContent
) || IsOpenPopoverWithInvoker(GetTopLevelScopeOwner(currentContent
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!GetTopLevelScopeOwner(currentContent) || IsOpenPopoverWithInvoker(GetTopLevelScopeOwner(currentContent))"
" (" "currentContent should be in top-level-scope at this point unless "
"for popover case" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 4516); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!GetTopLevelScopeOwner(currentContent) || IsOpenPopoverWithInvoker(GetTopLevelScopeOwner(currentContent))"
") (" "currentContent should be in top-level-scope at this point unless "
"for popover case" ")"); do { *((volatile int*)__null) = 4516
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
4513 !GetTopLevelScopeOwner(currentContent) ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!GetTopLevelScopeOwner(currentContent) || IsOpenPopoverWithInvoker
(GetTopLevelScopeOwner(currentContent)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!GetTopLevelScopeOwner(currentContent
) || IsOpenPopoverWithInvoker(GetTopLevelScopeOwner(currentContent
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!GetTopLevelScopeOwner(currentContent) || IsOpenPopoverWithInvoker(GetTopLevelScopeOwner(currentContent))"
" (" "currentContent should be in top-level-scope at this point unless "
"for popover case" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 4516); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!GetTopLevelScopeOwner(currentContent) || IsOpenPopoverWithInvoker(GetTopLevelScopeOwner(currentContent))"
") (" "currentContent should be in top-level-scope at this point unless "
"for popover case" ")"); do { *((volatile int*)__null) = 4516
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
4514 IsOpenPopoverWithInvoker(GetTopLevelScopeOwner(currentContent)),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!GetTopLevelScopeOwner(currentContent) || IsOpenPopoverWithInvoker
(GetTopLevelScopeOwner(currentContent)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!GetTopLevelScopeOwner(currentContent
) || IsOpenPopoverWithInvoker(GetTopLevelScopeOwner(currentContent
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!GetTopLevelScopeOwner(currentContent) || IsOpenPopoverWithInvoker(GetTopLevelScopeOwner(currentContent))"
" (" "currentContent should be in top-level-scope at this point unless "
"for popover case" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 4516); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!GetTopLevelScopeOwner(currentContent) || IsOpenPopoverWithInvoker(GetTopLevelScopeOwner(currentContent))"
") (" "currentContent should be in top-level-scope at this point unless "
"for popover case" ")"); do { *((volatile int*)__null) = 4516
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
4515 "currentContent should be in top-level-scope at this point unless "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!GetTopLevelScopeOwner(currentContent) || IsOpenPopoverWithInvoker
(GetTopLevelScopeOwner(currentContent)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!GetTopLevelScopeOwner(currentContent
) || IsOpenPopoverWithInvoker(GetTopLevelScopeOwner(currentContent
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!GetTopLevelScopeOwner(currentContent) || IsOpenPopoverWithInvoker(GetTopLevelScopeOwner(currentContent))"
" (" "currentContent should be in top-level-scope at this point unless "
"for popover case" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 4516); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!GetTopLevelScopeOwner(currentContent) || IsOpenPopoverWithInvoker(GetTopLevelScopeOwner(currentContent))"
") (" "currentContent should be in top-level-scope at this point unless "
"for popover case" ")"); do { *((volatile int*)__null) = 4516
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
4516 "for popover case")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!GetTopLevelScopeOwner(currentContent) || IsOpenPopoverWithInvoker
(GetTopLevelScopeOwner(currentContent)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!GetTopLevelScopeOwner(currentContent
) || IsOpenPopoverWithInvoker(GetTopLevelScopeOwner(currentContent
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!GetTopLevelScopeOwner(currentContent) || IsOpenPopoverWithInvoker(GetTopLevelScopeOwner(currentContent))"
" (" "currentContent should be in top-level-scope at this point unless "
"for popover case" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 4516); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!GetTopLevelScopeOwner(currentContent) || IsOpenPopoverWithInvoker(GetTopLevelScopeOwner(currentContent))"
") (" "currentContent should be in top-level-scope at this point unless "
"for popover case" ")"); do { *((volatile int*)__null) = 4516
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
4517
4518 // TabIndex not set defaults to 0 for form elements, anchors and other
4519 // elements that are normally focusable. Tabindex defaults to -1
4520 // for elements that are not normally focusable.
4521 // The returned computed tabindex from IsFocusable() is as follows:
4522 // clang-format off
4523 // < 0 not tabbable at all
4524 // == 0 in normal tab order (last after positive tabindexed items)
4525 // > 0 can be tabbed to in the order specified by this value
4526 // clang-format on
4527 int32_t tabIndex = frame->IsFocusable().mTabIndex;
4528
4529 LOGCONTENTNAVIGATION("Next Tabbable %s:", frame->GetContent())if ((__builtin_expect(!!(mozilla::detail::log_test(gFocusNavigationLog
, LogLevel::Debug)), 0))) { nsAutoCString tag("(none)"_ns); if
(frame->GetContent()) { frame->GetContent()->NodeInfo
()->NameAtom()->ToUTF8String(tag); } do { const ::mozilla
::LogModule* moz_real_module = gFocusNavigationLog; if ((__builtin_expect
(!!(mozilla::detail::log_test(moz_real_module, LogLevel::Debug
)), 0))) { mozilla::detail::log_print(moz_real_module, LogLevel
::Debug, "Next Tabbable %s:", tag.get()); } } while (0); }
;
4530 LOGFOCUSNAVIGATION(do { const ::mozilla::LogModule* moz_real_module = gFocusNavigationLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " with tabindex: %d expected: %d"
, tabIndex, aCurrentTabIndex); } } while (0)
4531 (" with tabindex: %d expected: %d", tabIndex, aCurrentTabIndex))do { const ::mozilla::LogModule* moz_real_module = gFocusNavigationLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " with tabindex: %d expected: %d"
, tabIndex, aCurrentTabIndex); } } while (0)
;
4532
4533 if (tabIndex >= 0) {
4534 NS_ASSERTION(currentContent,do { if (!(currentContent)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "IsFocusable set a tabindex for a frame with no content", "currentContent"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 4535); MOZ_PretendNoReturn(); } } while (0)
4535 "IsFocusable set a tabindex for a frame with no content")do { if (!(currentContent)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "IsFocusable set a tabindex for a frame with no content", "currentContent"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 4535); MOZ_PretendNoReturn(); } } while (0)
;
4536 if (!aForDocumentNavigation &&
4537 currentContent->IsHTMLElement(nsGkAtoms::img) &&
4538 currentContent->AsElement()->HasAttr(nsGkAtoms::usemap)) {
4539 // This is an image with a map. Image map areas are not traversed by
4540 // nsFrameIterator so look for the next or previous area element.
4541 nsIContent* areaContent = GetNextTabbableMapArea(
4542 aForward, aCurrentTabIndex, currentContent->AsElement(),
4543 iterStartContent);
4544 if (areaContent) {
4545 NS_ADDREF(*aResultContent = areaContent)(*aResultContent = areaContent)->AddRef();
4546 return NS_OK;
4547 }
4548 } else if (aIgnoreTabIndex || aCurrentTabIndex == tabIndex) {
4549 // break out if we've wrapped around to the start again.
4550 if (aOriginalStartContent &&
4551 currentContent == aOriginalStartContent) {
4552 NS_ADDREF(*aResultContent = currentContent)(*aResultContent = currentContent)->AddRef();
4553 return NS_OK;
4554 }
4555
4556 // If this is a remote child browser, call NavigateDocument to have
4557 // the child process continue the navigation. Return a special error
4558 // code to have the caller return early. If the child ends up not
4559 // being focusable in some way, the child process will call back
4560 // into document navigation again by calling MoveFocus.
4561 if (BrowserParent* remote = BrowserParent::GetFrom(currentContent)) {
4562 if (aNavigateByKey) {
4563 remote->NavigateByKey(aForward, aForDocumentNavigation);
4564 return NS_SUCCESS_DOM_NO_OPERATION;
4565 }
4566 return NS_OK;
4567 }
4568
4569 // Same as above but for out-of-process iframes
4570 if (auto* bbc = BrowserBridgeChild::GetFrom(currentContent)) {
4571 if (aNavigateByKey) {
4572 bbc->NavigateByKey(aForward, aForDocumentNavigation);
4573 return NS_SUCCESS_DOM_NO_OPERATION;
4574 }
4575 return NS_OK;
4576 }
4577
4578 // Next, for document navigation, check if this a non-remote child
4579 // document.
4580 bool checkSubDocument = true;
4581 if (aForDocumentNavigation &&
4582 TryDocumentNavigation(currentContent, &checkSubDocument,
4583 aResultContent)) {
4584 return NS_OK;
4585 }
4586
4587 if (checkSubDocument) {
4588 // found a node with a matching tab index. Check if it is a child
4589 // frame. If so, navigate into the child frame instead.
4590 if (TryToMoveFocusToSubDocument(
4591 currentContent, aOriginalStartContent, aForward,
4592 aForDocumentNavigation, aNavigateByKey,
4593 aReachedToEndForDocumentNavigation, aResultContent)) {
4594 MOZ_ASSERT(*aResultContent)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aResultContent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aResultContent))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("*aResultContent"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 4594); AnnotateMozCrashReason("MOZ_ASSERT" "(" "*aResultContent"
")"); do { *((volatile int*)__null) = 4594; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4595 return NS_OK;
4596 }
4597 // otherwise, use this as the next content node to tab to, unless
4598 // this was the element we started on. This would happen for
4599 // instance on an element with child frames, where frame navigation
4600 // could return the original element again. In that case, just skip
4601 // it. Also, if the next content node is the root content, then
4602 // return it. This latter case would happen only if someone made a
4603 // popup focusable.
4604 else if (currentContent == aRootContent ||
4605 currentContent != startContent) {
4606 NS_ADDREF(*aResultContent = currentContent)(*aResultContent = currentContent)->AddRef();
4607 return NS_OK;
4608 }
4609 } else if (currentContent && aReachedToEndForDocumentNavigation &&
4610 StaticPrefs::dom_disable_tab_focus_to_root_element() &&
4611 nsContentUtils::IsChromeDoc(
4612 currentContent->GetComposedDoc())) {
4613 // aReachedToEndForDocumentNavigation is true means
4614 // 1. This is a document navigation (i.e, VK_F6, Control + Tab)
4615 // 2. This is the top-level document (Note that we may start from
4616 // a subdocument)
4617 // 3. We've searched through the this top-level document already
4618 if (!GetRootForChildDocument(currentContent)) {
4619 // We'd like to focus the first focusable element of this
4620 // top-level chrome document.
4621 if (currentContent == aRootContent ||
4622 currentContent != startContent) {
4623 NS_ADDREF(*aResultContent = currentContent)(*aResultContent = currentContent)->AddRef();
4624 return NS_OK;
4625 }
4626 }
4627 }
4628 }
4629 } else if (aOriginalStartContent &&
4630 currentContent == aOriginalStartContent) {
4631 // not focusable, so return if we have wrapped around to the original
4632 // content. This is necessary in case the original starting content was
4633 // not focusable.
4634 //
4635 // FIXME: Shouldn't this return null instead? currentContent isn't
4636 // focusable after all.
4637 NS_ADDREF(*aResultContent = currentContent)(*aResultContent = currentContent)->AddRef();
4638 return NS_OK;
4639 }
4640
4641 // Move to the next or previous frame, but ignore continuation frames
4642 // since only the first frame should be involved in focusability.
4643 // Otherwise, a loop will occur in the following example:
4644 // <span tabindex="1">...<a/><a/>...</span>
4645 // where the text wraps onto multiple lines. Tabbing from the second
4646 // link can find one of the span's continuation frames between the link
4647 // and the end of the span, and the span would end up getting focused
4648 // again.
4649 do {
4650 if (aForward) {
4651 frameIterator->Next();
4652 } else {
4653 frameIterator->Prev();
4654 }
4655 frame = frameIterator->CurrentItem();
4656 } while (frame && frame->GetPrevContinuation());
4657 }
4658
4659 // If already at lowest priority tab (0), end search completely.
4660 // A bit counterintuitive but true, tabindex order goes 1, 2, ... 32767, 0
4661 if (aCurrentTabIndex == (aForward ? 0 : 1)) {
4662 // if going backwards, the canvas should be focused once the beginning
4663 // has been reached, so get the root element.
4664 if (!aForward && !StaticPrefs::dom_disable_tab_focus_to_root_element()) {
4665 nsCOMPtr<nsPIDOMWindowOuter> window = GetCurrentWindow(aRootContent);
4666 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(window)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "window" ") failed", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 4666); return NS_ERROR_FAILURE; } } while (false)
;
4667
4668 RefPtr<Element> docRoot = GetRootForFocus(
4669 window, aRootContent->GetComposedDoc(), false, true);
4670 FocusFirst(docRoot, aResultContent,
4671 false /* aReachedToEndForDocumentNavigation */);
4672 }
4673 break;
4674 }
4675
4676 // continue looking for next highest priority tabindex
4677 aCurrentTabIndex =
4678 GetNextTabIndex(aRootContent, aCurrentTabIndex, aForward);
4679 startContent = iterStartContent = aRootContent;
4680 currentTopLevelScopeOwner = GetTopLevelScopeOwner(startContent);
4681 }
4682
4683 return NS_OK;
4684}
4685
4686bool nsFocusManager::TryDocumentNavigation(nsIContent* aCurrentContent,
4687 bool* aCheckSubDocument,
4688 nsIContent** aResultContent) {
4689 *aCheckSubDocument = true;
4690 if (RefPtr<Element> rootElementForChildDocument =
4691 GetRootForChildDocument(aCurrentContent)) {
4692 // If GetRootForChildDocument returned something then call
4693 // FocusFirst to find the root or first element to focus within
4694 // the child document. If this is a frameset though, skip this and
4695 // fall through to normal tab navigation to iterate into
4696 // the frameset's frames and locate the first focusable frame.
4697 if (!rootElementForChildDocument->IsHTMLElement(nsGkAtoms::frameset)) {
4698 *aCheckSubDocument = false;
4699 Unused << FocusFirst(rootElementForChildDocument, aResultContent,
4700 false /* aReachedToEndForDocumentNavigation */);
4701 return *aResultContent != nullptr;
4702 }
4703 } else {
4704 // Set aCheckSubDocument to false, as this was neither a frame
4705 // type element or a child document that was focusable.
4706 *aCheckSubDocument = false;
4707 }
4708
4709 return false;
4710}
4711
4712bool nsFocusManager::TryToMoveFocusToSubDocument(
4713 nsIContent* aCurrentContent, nsIContent* aOriginalStartContent,
4714 bool aForward, bool aForDocumentNavigation, bool aNavigateByKey,
4715 bool aReachedToEndForDocumentNavigation, nsIContent** aResultContent) {
4716 Document* doc = aCurrentContent->GetComposedDoc();
4717 NS_ASSERTION(doc, "content not in document")do { if (!(doc)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "content not in document"
, "doc", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 4717); MOZ_PretendNoReturn(); } } while (0)
;
4718 Document* subdoc = doc->GetSubDocumentFor(aCurrentContent);
4719 if (subdoc && !subdoc->EventHandlingSuppressed()) {
4720 if (aForward && !StaticPrefs::dom_disable_tab_focus_to_root_element()) {
4721 // When tabbing forward into a frame, return the root
4722 // frame so that the canvas becomes focused.
4723 if (nsCOMPtr<nsPIDOMWindowOuter> subframe = subdoc->GetWindow()) {
4724 *aResultContent = GetRootForFocus(subframe, subdoc, false, true);
4725 if (*aResultContent) {
4726 NS_ADDREF(*aResultContent)(*aResultContent)->AddRef();
4727 return true;
4728 }
4729 }
4730 }
4731 if (RefPtr<Element> rootElement = subdoc->GetRootElement()) {
4732 if (RefPtr<PresShell> subPresShell = subdoc->GetPresShell()) {
4733 nsresult rv = GetNextTabbableContent(
4734 subPresShell, rootElement, aOriginalStartContent, rootElement,
4735 aForward, (aForward ? 1 : 0), false, aForDocumentNavigation,
4736 aNavigateByKey, false, aReachedToEndForDocumentNavigation,
4737 aResultContent);
4738 NS_ENSURE_SUCCESS(rv, false)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", "false", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 4738); return false; } } while (false)
;
4739 if (*aResultContent) {
4740 return true;
4741 }
4742 if (rootElement->IsEditable() &&
4743 StaticPrefs::dom_disable_tab_focus_to_root_element()) {
4744 // Only move to the root element with a valid reason
4745 *aResultContent = rootElement;
4746 NS_ADDREF(*aResultContent)(*aResultContent)->AddRef();
4747 return true;
4748 }
4749 }
4750 }
4751 }
4752 return false;
4753}
4754
4755nsIContent* nsFocusManager::GetNextTabbableMapArea(bool aForward,
4756 int32_t aCurrentTabIndex,
4757 Element* aImageContent,
4758 nsIContent* aStartContent) {
4759 if (aImageContent->IsInComposedDoc()) {
4760 HTMLImageElement* imgElement = HTMLImageElement::FromNode(aImageContent);
4761 // The caller should check the element type, so we can assert here.
4762 MOZ_ASSERT(imgElement)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(imgElement)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(imgElement))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("imgElement", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 4762); AnnotateMozCrashReason("MOZ_ASSERT" "(" "imgElement"
")"); do { *((volatile int*)__null) = 4762; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4763
4764 nsCOMPtr<nsIContent> mapContent = imgElement->FindImageMap();
4765 if (!mapContent) {
4766 return nullptr;
4767 }
4768 // First see if the the start content is in this map
4769 Maybe<uint32_t> indexOfStartContent =
4770 mapContent->ComputeIndexOf(aStartContent);
4771 nsIContent* scanStartContent;
4772 Focusable focusable;
4773 if (indexOfStartContent.isNothing() ||
4774 ((focusable = aStartContent->IsFocusableWithoutStyle()) &&
4775 focusable.mTabIndex != aCurrentTabIndex)) {
4776 // If aStartContent is in this map we must start iterating past it.
4777 // We skip the case where aStartContent has tabindex == aStartContent
4778 // since the next tab ordered element might be before it
4779 // (or after for backwards) in the child list.
4780 scanStartContent =
4781 aForward ? mapContent->GetFirstChild() : mapContent->GetLastChild();
4782 } else {
4783 scanStartContent = aForward ? aStartContent->GetNextSibling()
4784 : aStartContent->GetPreviousSibling();
4785 }
4786
4787 for (nsCOMPtr<nsIContent> areaContent = scanStartContent; areaContent;
4788 areaContent = aForward ? areaContent->GetNextSibling()
4789 : areaContent->GetPreviousSibling()) {
4790 focusable = areaContent->IsFocusableWithoutStyle();
4791 if (focusable && focusable.mTabIndex == aCurrentTabIndex) {
4792 return areaContent;
4793 }
4794 }
4795 }
4796
4797 return nullptr;
4798}
4799
4800int32_t nsFocusManager::GetNextTabIndex(nsIContent* aParent,
4801 int32_t aCurrentTabIndex,
4802 bool aForward) {
4803 int32_t tabIndex, childTabIndex;
4804 StyleChildrenIterator iter(aParent);
4805
4806 if (aForward) {
4807 tabIndex = 0;
4808 for (nsIContent* child = iter.GetNextChild(); child;
4809 child = iter.GetNextChild()) {
4810 // Skip child's descendants if child is a shadow host or slot, as they are
4811 // in the focus navigation scope owned by child's shadow root
4812 if (!IsHostOrSlot(child)) {
4813 childTabIndex = GetNextTabIndex(child, aCurrentTabIndex, aForward);
4814 if (childTabIndex > aCurrentTabIndex && childTabIndex != tabIndex) {
4815 tabIndex = (tabIndex == 0 || childTabIndex < tabIndex) ? childTabIndex
4816 : tabIndex;
4817 }
4818 }
4819
4820 nsAutoString tabIndexStr;
4821 if (child->IsElement()) {
4822 child->AsElement()->GetAttr(nsGkAtoms::tabindex, tabIndexStr);
4823 }
4824 nsresult ec;
4825 int32_t val = tabIndexStr.ToInteger(&ec);
4826 if (NS_SUCCEEDED(ec)((bool)(__builtin_expect(!!(!NS_FAILED_impl(ec)), 1))) && val > aCurrentTabIndex && val != tabIndex) {
4827 tabIndex = (tabIndex == 0 || val < tabIndex) ? val : tabIndex;
4828 }
4829 }
4830 } else { /* !aForward */
4831 tabIndex = 1;
4832 for (nsIContent* child = iter.GetNextChild(); child;
4833 child = iter.GetNextChild()) {
4834 // Skip child's descendants if child is a shadow host or slot, as they are
4835 // in the focus navigation scope owned by child's shadow root
4836 if (!IsHostOrSlot(child)) {
4837 childTabIndex = GetNextTabIndex(child, aCurrentTabIndex, aForward);
4838 if ((aCurrentTabIndex == 0 && childTabIndex > tabIndex) ||
4839 (childTabIndex < aCurrentTabIndex && childTabIndex > tabIndex)) {
4840 tabIndex = childTabIndex;
4841 }
4842 }
4843
4844 nsAutoString tabIndexStr;
4845 if (child->IsElement()) {
4846 child->AsElement()->GetAttr(nsGkAtoms::tabindex, tabIndexStr);
4847 }
4848 nsresult ec;
4849 int32_t val = tabIndexStr.ToInteger(&ec);
4850 if (NS_SUCCEEDED(ec)((bool)(__builtin_expect(!!(!NS_FAILED_impl(ec)), 1)))) {
4851 if ((aCurrentTabIndex == 0 && val > tabIndex) ||
4852 (val < aCurrentTabIndex && val > tabIndex)) {
4853 tabIndex = val;
4854 }
4855 }
4856 }
4857 }
4858
4859 return tabIndex;
4860}
4861
4862nsresult nsFocusManager::FocusFirst(Element* aRootElement,
4863 nsIContent** aNextContent,
4864 bool aReachedToEndForDocumentNavigation) {
4865 if (!aRootElement) {
4866 return NS_OK;
4867 }
4868
4869 Document* doc = aRootElement->GetComposedDoc();
4870 if (doc) {
4871 if (nsContentUtils::IsChromeDoc(doc)) {
4872 // If the redirectdocumentfocus attribute is set, redirect the focus to a
4873 // specific element. This is primarily used to retarget the focus to the
4874 // urlbar during document navigation.
4875 nsAutoString retarget;
4876
4877 if (aRootElement->GetAttr(nsGkAtoms::retargetdocumentfocus, retarget)) {
4878 RefPtr<Element> element = doc->GetElementById(retarget);
4879 nsCOMPtr<nsIContent> retargetElement =
4880 FlushAndCheckIfFocusable(element, 0);
4881 if (retargetElement) {
4882 retargetElement.forget(aNextContent);
4883 return NS_OK;
4884 }
4885 }
4886 }
4887
4888 nsCOMPtr<nsIDocShell> docShell = doc->GetDocShell();
4889 if (docShell->ItemType() == nsIDocShellTreeItem::typeChrome) {
4890 // If the found content is in a chrome shell, navigate forward one
4891 // tabbable item so that the first item is focused. Note that we
4892 // always go forward and not back here.
4893 if (RefPtr<PresShell> presShell = doc->GetPresShell()) {
4894 return GetNextTabbableContent(
4895 presShell, aRootElement, nullptr, aRootElement, true, 1, false,
4896 StaticPrefs::dom_disable_tab_focus_to_root_element()
4897 ? aReachedToEndForDocumentNavigation
4898 : false,
4899 true, false, aReachedToEndForDocumentNavigation, aNextContent);
4900 }
4901 }
4902 }
4903
4904 NS_ADDREF(*aNextContent = aRootElement)(*aNextContent = aRootElement)->AddRef();
4905 return NS_OK;
4906}
4907
4908Element* nsFocusManager::GetRootForFocus(nsPIDOMWindowOuter* aWindow,
4909 Document* aDocument,
4910 bool aForDocumentNavigation,
4911 bool aCheckVisibility) {
4912 if (!aForDocumentNavigation) {
4913 nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
4914 if (docShell->ItemType() == nsIDocShellTreeItem::typeChrome) {
4915 return nullptr;
4916 }
4917 }
4918
4919 if (aCheckVisibility && !IsWindowVisible(aWindow)) return nullptr;
4920
4921 // If the body is contenteditable, use the editor's root element rather than
4922 // the actual root element.
4923 RefPtr<Element> rootElement =
4924 nsLayoutUtils::GetEditableRootContentByContentEditable(aDocument);
4925 if (!rootElement || !rootElement->GetPrimaryFrame()) {
4926 rootElement = aDocument->GetRootElement();
4927 if (!rootElement) {
4928 return nullptr;
4929 }
4930 }
4931
4932 if (aCheckVisibility && !rootElement->GetPrimaryFrame()) {
4933 return nullptr;
4934 }
4935
4936 // Finally, check if this is a frameset
4937 if (aDocument && aDocument->IsHTMLOrXHTML()) {
4938 Element* htmlChild = aDocument->GetHtmlChildElement(nsGkAtoms::frameset);
4939 if (htmlChild) {
4940 // In document navigation mode, return the frameset so that navigation
4941 // descends into the child frames.
4942 return aForDocumentNavigation ? htmlChild : nullptr;
4943 }
4944 }
4945
4946 return rootElement;
4947}
4948
4949Element* nsFocusManager::GetRootForChildDocument(nsIContent* aContent) {
4950 // Check for elements that represent child documents, that is, browsers,
4951 // editors or frames from a frameset. We don't include iframes since we
4952 // consider them to be an integral part of the same window or page.
4953 if (!aContent || !(aContent->IsXULElement(nsGkAtoms::browser) ||
4954 aContent->IsXULElement(nsGkAtoms::editor) ||
4955 aContent->IsHTMLElement(nsGkAtoms::frame))) {
4956 return nullptr;
4957 }
4958
4959 Document* doc = aContent->GetComposedDoc();
4960 if (!doc) {
4961 return nullptr;
4962 }
4963
4964 Document* subdoc = doc->GetSubDocumentFor(aContent);
4965 if (!subdoc || subdoc->EventHandlingSuppressed()) {
4966 return nullptr;
4967 }
4968
4969 nsCOMPtr<nsPIDOMWindowOuter> window = subdoc->GetWindow();
4970 return GetRootForFocus(window, subdoc, true, true);
4971}
4972
4973static bool IsLink(nsIContent* aContent) {
4974 return aContent->IsElement() && aContent->AsElement()->IsLink();
4975}
4976
4977void nsFocusManager::GetFocusInSelection(nsPIDOMWindowOuter* aWindow,
4978 nsIContent* aStartSelection,
4979 nsIContent* aEndSelection,
4980 nsIContent** aFocusedContent) {
4981 *aFocusedContent = nullptr;
4982
4983 nsCOMPtr<nsIContent> testContent = aStartSelection;
4984 nsCOMPtr<nsIContent> nextTestContent = aEndSelection;
4985
4986 nsCOMPtr<nsIContent> currentFocus = aWindow->GetFocusedElement();
4987
4988 // We now have the correct start node in selectionContent!
4989 // Search for focusable elements, starting with selectionContent
4990
4991 // Method #1: Keep going up while we look - an ancestor might be focusable
4992 // We could end the loop earlier, such as when we're no longer
4993 // in the same frame, by comparing selectionContent->GetPrimaryFrame()
4994 // with a variable holding the starting selectionContent
4995 while (testContent) {
4996 // Keep testing while selectionContent is equal to something,
4997 // eventually we'll run out of ancestors
4998
4999 if (testContent == currentFocus || IsLink(testContent)) {
5000 testContent.forget(aFocusedContent);
5001 return;
5002 }
5003
5004 // Get the parent
5005 testContent = testContent->GetParent();
5006
5007 if (!testContent) {
5008 // We run this loop again, checking the ancestor chain of the selection's
5009 // end point
5010 testContent = nextTestContent;
5011 nextTestContent = nullptr;
5012 }
5013 }
5014
5015 // We couldn't find an anchor that was an ancestor of the selection start
5016 // Method #2: look for anchor in selection's primary range (depth first
5017 // search)
5018
5019 nsCOMPtr<nsIContent> selectionNode = aStartSelection;
5020 nsCOMPtr<nsIContent> endSelectionNode = aEndSelection;
5021 nsCOMPtr<nsIContent> testNode;
5022
5023 do {
5024 testContent = selectionNode;
5025
5026 // We're looking for any focusable link that could be part of the
5027 // main document's selection.
5028 if (testContent == currentFocus || IsLink(testContent)) {
5029 testContent.forget(aFocusedContent);
5030 return;
5031 }
5032
5033 nsIContent* testNode = selectionNode->GetFirstChild();
5034 if (testNode) {
5035 selectionNode = testNode;
5036 continue;
5037 }
5038
5039 if (selectionNode == endSelectionNode) {
5040 break;
5041 }
5042 testNode = selectionNode->GetNextSibling();
5043 if (testNode) {
5044 selectionNode = testNode;
5045 continue;
5046 }
5047
5048 do {
5049 // GetParent is OK here, instead of GetParentNode, because the only case
5050 // where the latter returns something different from the former is when
5051 // GetParentNode is the document. But in that case we would simply get
5052 // null for selectionNode when setting it to testNode->GetNextSibling()
5053 // (because a document has no next sibling). And then the next iteration
5054 // of this loop would get null for GetParentNode anyway, and break out of
5055 // all the loops.
5056 testNode = selectionNode->GetParent();
5057 if (!testNode || testNode == endSelectionNode) {
5058 selectionNode = nullptr;
5059 break;
5060 }
5061 selectionNode = testNode->GetNextSibling();
5062 if (selectionNode) {
5063 break;
5064 }
5065 selectionNode = testNode;
5066 } while (true);
5067 } while (selectionNode && selectionNode != endSelectionNode);
5068}
5069
5070static void MaybeUnlockPointer(BrowsingContext* aCurrentFocusedContext) {
5071 if (!PointerLockManager::IsInLockContext(aCurrentFocusedContext)) {
5072 PointerLockManager::Unlock();
5073 }
5074}
5075
5076class PointerUnlocker : public Runnable {
5077 public:
5078 PointerUnlocker() : mozilla::Runnable("PointerUnlocker") {
5079 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5079); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 5079; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5080 MOZ_ASSERT(!PointerUnlocker::sActiveUnlocker)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!PointerUnlocker::sActiveUnlocker)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!PointerUnlocker::sActiveUnlocker
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!PointerUnlocker::sActiveUnlocker", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5080); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!PointerUnlocker::sActiveUnlocker"
")"); do { *((volatile int*)__null) = 5080; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5081 PointerUnlocker::sActiveUnlocker = this;
5082 }
5083
5084 ~PointerUnlocker() {
5085 if (PointerUnlocker::sActiveUnlocker == this) {
5086 PointerUnlocker::sActiveUnlocker = nullptr;
5087 }
5088 }
5089
5090 NS_IMETHODvirtual nsresult Run() override {
5091 if (PointerUnlocker::sActiveUnlocker == this) {
5092 PointerUnlocker::sActiveUnlocker = nullptr;
5093 }
5094 NS_ENSURE_STATE(nsFocusManager::GetFocusManager())do { if ((__builtin_expect(!!(!(nsFocusManager::GetFocusManager
())), 0))) { NS_DebugBreak(NS_DEBUG_WARNING, "NS_ENSURE_TRUE("
"nsFocusManager::GetFocusManager()" ") failed", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5094); return NS_ERROR_UNEXPECTED; } } while (false)
;
5095 nsPIDOMWindowOuter* focused =
5096 nsFocusManager::GetFocusManager()->GetFocusedWindow();
5097 MaybeUnlockPointer(focused ? focused->GetBrowsingContext() : nullptr);
5098 return NS_OK;
5099 }
5100
5101 static PointerUnlocker* sActiveUnlocker;
5102};
5103
5104PointerUnlocker* PointerUnlocker::sActiveUnlocker = nullptr;
5105
5106void nsFocusManager::SetFocusedBrowsingContext(BrowsingContext* aContext,
5107 uint64_t aActionId) {
5108 if (XRE_IsParentProcess()) {
5109 return;
5110 }
5111 MOZ_ASSERT(!ActionIdComparableAndLower(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!ActionIdComparableAndLower( aActionId, mActionIdForFocusedBrowsingContextInContent
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!ActionIdComparableAndLower( aActionId, mActionIdForFocusedBrowsingContextInContent
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!ActionIdComparableAndLower( aActionId, mActionIdForFocusedBrowsingContextInContent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5112); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!ActionIdComparableAndLower( aActionId, mActionIdForFocusedBrowsingContextInContent)"
")"); do { *((volatile int*)__null) = 5112; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5112 aActionId, mActionIdForFocusedBrowsingContextInContent))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!ActionIdComparableAndLower( aActionId, mActionIdForFocusedBrowsingContextInContent
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!ActionIdComparableAndLower( aActionId, mActionIdForFocusedBrowsingContextInContent
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!ActionIdComparableAndLower( aActionId, mActionIdForFocusedBrowsingContextInContent)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5112); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!ActionIdComparableAndLower( aActionId, mActionIdForFocusedBrowsingContextInContent)"
")"); do { *((volatile int*)__null) = 5112; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5113 mFocusedBrowsingContextInContent = aContext;
5114 mActionIdForFocusedBrowsingContextInContent = aActionId;
5115 if (aContext) {
5116 // We don't send the unset but instead expect the set from
5117 // elsewhere to take care of it. XXX Is that bad?
5118 MOZ_ASSERT(aContext->IsInProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContext->IsInProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aContext->IsInProcess()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aContext->IsInProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5118); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContext->IsInProcess()"
")"); do { *((volatile int*)__null) = 5118; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5119 mozilla::dom::ContentChild* contentChild =
5120 mozilla::dom::ContentChild::GetSingleton();
5121 MOZ_ASSERT(contentChild)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(contentChild)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(contentChild))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("contentChild", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5121); AnnotateMozCrashReason("MOZ_ASSERT" "(" "contentChild"
")"); do { *((volatile int*)__null) = 5121; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5122 contentChild->SendSetFocusedBrowsingContext(aContext, aActionId);
5123 }
5124}
5125
5126void nsFocusManager::SetFocusedBrowsingContextFromOtherProcess(
5127 BrowsingContext* aContext, uint64_t aActionId) {
5128 MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5128); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 5128; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5129 MOZ_ASSERT(aContext)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aContext))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aContext", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5129); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContext" ")"
); do { *((volatile int*)__null) = 5129; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5130 if (ActionIdComparableAndLower(aActionId,
5131 mActionIdForFocusedBrowsingContextInContent)) {
5132 // Unclear if this ever happens.
5133 LOGFOCUS(do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set an in-process BrowsingContext [%p] as "
"focused from another process due to stale action id %" "l" "u"
".", aContext, aActionId); } } while (0)
5134 ("Ignored an attempt to set an in-process BrowsingContext [%p] as "do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set an in-process BrowsingContext [%p] as "
"focused from another process due to stale action id %" "l" "u"
".", aContext, aActionId); } } while (0)
5135 "focused from another process due to stale action id %" PRIu64 ".",do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set an in-process BrowsingContext [%p] as "
"focused from another process due to stale action id %" "l" "u"
".", aContext, aActionId); } } while (0)
5136 aContext, aActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set an in-process BrowsingContext [%p] as "
"focused from another process due to stale action id %" "l" "u"
".", aContext, aActionId); } } while (0)
;
5137 return;
5138 }
5139 if (aContext->IsInProcess()) {
5140 // This message has been in transit for long enough that
5141 // the process association of aContext has changed since
5142 // the other content process sent the message, because
5143 // an iframe in that process became an out-of-process
5144 // iframe while the IPC broadcast that we're receiving
5145 // was in-flight. Let's just ignore this.
5146 LOGFOCUS(do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set an in-process BrowsingContext [%p] as "
"focused from another process, actionid: %" "l" "u" ".", aContext
, aActionId); } } while (0)
5147 ("Ignored an attempt to set an in-process BrowsingContext [%p] as "do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set an in-process BrowsingContext [%p] as "
"focused from another process, actionid: %" "l" "u" ".", aContext
, aActionId); } } while (0)
5148 "focused from another process, actionid: %" PRIu64 ".",do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set an in-process BrowsingContext [%p] as "
"focused from another process, actionid: %" "l" "u" ".", aContext
, aActionId); } } while (0)
5149 aContext, aActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set an in-process BrowsingContext [%p] as "
"focused from another process, actionid: %" "l" "u" ".", aContext
, aActionId); } } while (0)
;
5150 return;
5151 }
5152 mFocusedBrowsingContextInContent = aContext;
5153 mActionIdForFocusedBrowsingContextInContent = aActionId;
5154 mFocusedElement = nullptr;
5155 mFocusedWindow = nullptr;
5156}
5157
5158bool nsFocusManager::SetFocusedBrowsingContextInChrome(
5159 mozilla::dom::BrowsingContext* aContext, uint64_t aActionId) {
5160 MOZ_ASSERT(aActionId)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aActionId)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aActionId))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aActionId", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5160); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aActionId" ")"
); do { *((volatile int*)__null) = 5160; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5161 if (ProcessPendingFocusedBrowsingContextActionId(aActionId)) {
5162 MOZ_DIAGNOSTIC_ASSERT(!ActionIdComparableAndLower(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!ActionIdComparableAndLower( aActionId, mActionIdForFocusedBrowsingContextInChrome
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!ActionIdComparableAndLower( aActionId, mActionIdForFocusedBrowsingContextInChrome
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!ActionIdComparableAndLower( aActionId, mActionIdForFocusedBrowsingContextInChrome)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5163); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!ActionIdComparableAndLower( aActionId, mActionIdForFocusedBrowsingContextInChrome)"
")"); do { *((volatile int*)__null) = 5163; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5163 aActionId, mActionIdForFocusedBrowsingContextInChrome))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!ActionIdComparableAndLower( aActionId, mActionIdForFocusedBrowsingContextInChrome
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!ActionIdComparableAndLower( aActionId, mActionIdForFocusedBrowsingContextInChrome
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!ActionIdComparableAndLower( aActionId, mActionIdForFocusedBrowsingContextInChrome)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5163); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!ActionIdComparableAndLower( aActionId, mActionIdForFocusedBrowsingContextInChrome)"
")"); do { *((volatile int*)__null) = 5163; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5164 mFocusedBrowsingContextInChrome = aContext;
5165 mActionIdForFocusedBrowsingContextInChrome = aActionId;
5166 return true;
5167 }
5168 return false;
5169}
5170
5171BrowsingContext* nsFocusManager::GetFocusedBrowsingContextInChrome() {
5172 return mFocusedBrowsingContextInChrome;
5173}
5174
5175void nsFocusManager::BrowsingContextDetached(BrowsingContext* aContext) {
5176 if (mFocusedBrowsingContextInChrome == aContext) {
5177 mFocusedBrowsingContextInChrome = nullptr;
5178 // Deliberately not adjusting the corresponding action id, because
5179 // we don't want changes from the past to take effect.
5180 }
5181 if (mActiveBrowsingContextInChrome == aContext) {
5182 mActiveBrowsingContextInChrome = nullptr;
5183 // Deliberately not adjusting the corresponding action id, because
5184 // we don't want changes from the past to take effect.
5185 }
5186}
5187
5188void nsFocusManager::SetActiveBrowsingContextInContent(
5189 mozilla::dom::BrowsingContext* aContext, uint64_t aActionId,
5190 bool aIsEnteringBFCache) {
5191 MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5191); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 5191; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5192 MOZ_ASSERT(!aContext || aContext->IsInProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aContext || aContext->IsInProcess())>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!aContext || aContext->IsInProcess()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!aContext || aContext->IsInProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5192); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aContext || aContext->IsInProcess()"
")"); do { *((volatile int*)__null) = 5192; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5193 mozilla::dom::ContentChild* contentChild =
5194 mozilla::dom::ContentChild::GetSingleton();
5195 MOZ_ASSERT(contentChild)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(contentChild)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(contentChild))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("contentChild", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5195); AnnotateMozCrashReason("MOZ_ASSERT" "(" "contentChild"
")"); do { *((volatile int*)__null) = 5195; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5196
5197 if (ActionIdComparableAndLower(aActionId,
5198 mActionIdForActiveBrowsingContextInContent)) {
5199 LOGFOCUS(do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set an in-process BrowsingContext [%p] as "
"the active browsing context due to a stale action id %" "l"
"u" ".", aContext, aActionId); } } while (0)
5200 ("Ignored an attempt to set an in-process BrowsingContext [%p] as "do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set an in-process BrowsingContext [%p] as "
"the active browsing context due to a stale action id %" "l"
"u" ".", aContext, aActionId); } } while (0)
5201 "the active browsing context due to a stale action id %" PRIu64 ".",do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set an in-process BrowsingContext [%p] as "
"the active browsing context due to a stale action id %" "l"
"u" ".", aContext, aActionId); } } while (0)
5202 aContext, aActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set an in-process BrowsingContext [%p] as "
"the active browsing context due to a stale action id %" "l"
"u" ".", aContext, aActionId); } } while (0)
;
5203 return;
5204 }
5205
5206 if (aContext != mActiveBrowsingContextInContent) {
5207 if (aContext) {
5208 contentChild->SendSetActiveBrowsingContext(aContext, aActionId);
5209 } else if (mActiveBrowsingContextInContent &&
5210 !(BFCacheInParent() && aIsEnteringBFCache)) {
5211 // No need to tell the parent process to update the active browsing
5212 // context to null if we are entering BFCache, because the browsing
5213 // context that is about to show will update it.
5214 //
5215 // We want to sync this over only if this isn't happening
5216 // due to the active BrowsingContext switching processes,
5217 // in which case the BrowserChild has already marked itself
5218 // as destroying.
5219 nsPIDOMWindowOuter* outer =
5220 mActiveBrowsingContextInContent->GetDOMWindow();
5221 if (outer) {
5222 nsPIDOMWindowInner* inner = outer->GetCurrentInnerWindow();
5223 if (inner) {
5224 WindowGlobalChild* globalChild = inner->GetWindowGlobalChild();
5225 if (globalChild) {
5226 RefPtr<BrowserChild> browserChild = globalChild->GetBrowserChild();
5227 if (browserChild && !browserChild->IsDestroyed()) {
5228 contentChild->SendUnsetActiveBrowsingContext(
5229 mActiveBrowsingContextInContent, aActionId);
5230 }
5231 }
5232 }
5233 }
5234 }
5235 }
5236 mActiveBrowsingContextInContentSetFromOtherProcess = false;
5237 mActiveBrowsingContextInContent = aContext;
5238 mActionIdForActiveBrowsingContextInContent = aActionId;
5239 MaybeUnlockPointer(aContext);
5240}
5241
5242void nsFocusManager::SetActiveBrowsingContextFromOtherProcess(
5243 BrowsingContext* aContext, uint64_t aActionId) {
5244 MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5244); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 5244; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5245 MOZ_ASSERT(aContext)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aContext))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aContext", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5245); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContext" ")"
); do { *((volatile int*)__null) = 5245; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5246 if (ActionIdComparableAndLower(aActionId,
5247 mActionIdForActiveBrowsingContextInContent)) {
5248 LOGFOCUS(do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set active BrowsingContext [%p] from "
"another process due to a stale action id %" "l" "u" ".", aContext
, aActionId); } } while (0)
5249 ("Ignored an attempt to set active BrowsingContext [%p] from "do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set active BrowsingContext [%p] from "
"another process due to a stale action id %" "l" "u" ".", aContext
, aActionId); } } while (0)
5250 "another process due to a stale action id %" PRIu64 ".",do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set active BrowsingContext [%p] from "
"another process due to a stale action id %" "l" "u" ".", aContext
, aActionId); } } while (0)
5251 aContext, aActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set active BrowsingContext [%p] from "
"another process due to a stale action id %" "l" "u" ".", aContext
, aActionId); } } while (0)
;
5252 return;
5253 }
5254 if (aContext->IsInProcess()) {
5255 // This message has been in transit for long enough that
5256 // the process association of aContext has changed since
5257 // the other content process sent the message, because
5258 // an iframe in that process became an out-of-process
5259 // iframe while the IPC broadcast that we're receiving
5260 // was in-flight. Let's just ignore this.
5261 LOGFOCUS(do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set an in-process BrowsingContext [%p] as "
"active from another process. actionid: %" "l" "u", aContext
, aActionId); } } while (0)
5262 ("Ignored an attempt to set an in-process BrowsingContext [%p] as "do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set an in-process BrowsingContext [%p] as "
"active from another process. actionid: %" "l" "u", aContext
, aActionId); } } while (0)
5263 "active from another process. actionid: %" PRIu64,do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set an in-process BrowsingContext [%p] as "
"active from another process. actionid: %" "l" "u", aContext
, aActionId); } } while (0)
5264 aContext, aActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set an in-process BrowsingContext [%p] as "
"active from another process. actionid: %" "l" "u", aContext
, aActionId); } } while (0)
;
5265 return;
5266 }
5267 mActiveBrowsingContextInContentSetFromOtherProcess = true;
5268 mActiveBrowsingContextInContent = aContext;
5269 mActionIdForActiveBrowsingContextInContent = aActionId;
5270 MaybeUnlockPointer(aContext);
5271}
5272
5273void nsFocusManager::UnsetActiveBrowsingContextFromOtherProcess(
5274 BrowsingContext* aContext, uint64_t aActionId) {
5275 MOZ_ASSERT(!XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!XRE_IsParentProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("!XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5275); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 5275; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5276 MOZ_ASSERT(aContext)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aContext)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aContext))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aContext", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5276); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aContext" ")"
); do { *((volatile int*)__null) = 5276; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5277 if (ActionIdComparableAndLower(aActionId,
5278 mActionIdForActiveBrowsingContextInContent)) {
5279 LOGFOCUS(do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to unset the active BrowsingContext [%p] from "
"another process due to stale action id: %" "l" "u" ".", aContext
, aActionId); } } while (0)
5280 ("Ignored an attempt to unset the active BrowsingContext [%p] from "do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to unset the active BrowsingContext [%p] from "
"another process due to stale action id: %" "l" "u" ".", aContext
, aActionId); } } while (0)
5281 "another process due to stale action id: %" PRIu64 ".",do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to unset the active BrowsingContext [%p] from "
"another process due to stale action id: %" "l" "u" ".", aContext
, aActionId); } } while (0)
5282 aContext, aActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to unset the active BrowsingContext [%p] from "
"another process due to stale action id: %" "l" "u" ".", aContext
, aActionId); } } while (0)
;
5283 return;
5284 }
5285 if (mActiveBrowsingContextInContent == aContext) {
5286 mActiveBrowsingContextInContent = nullptr;
5287 mActionIdForActiveBrowsingContextInContent = aActionId;
5288 MaybeUnlockPointer(nullptr);
5289 } else {
5290 LOGFOCUS(do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to unset the active BrowsingContext [%p] from "
"another process. actionid: %" "l" "u", aContext, aActionId)
; } } while (0)
5291 ("Ignored an attempt to unset the active BrowsingContext [%p] from "do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to unset the active BrowsingContext [%p] from "
"another process. actionid: %" "l" "u", aContext, aActionId)
; } } while (0)
5292 "another process. actionid: %" PRIu64,do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to unset the active BrowsingContext [%p] from "
"another process. actionid: %" "l" "u", aContext, aActionId)
; } } while (0)
5293 aContext, aActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to unset the active BrowsingContext [%p] from "
"another process. actionid: %" "l" "u", aContext, aActionId)
; } } while (0)
;
5294 }
5295}
5296
5297void nsFocusManager::ReviseActiveBrowsingContext(
5298 uint64_t aOldActionId, mozilla::dom::BrowsingContext* aContext,
5299 uint64_t aNewActionId) {
5300 MOZ_ASSERT(XRE_IsContentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsContentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsContentProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsContentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5300); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsContentProcess()"
")"); do { *((volatile int*)__null) = 5300; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5301 if (mActionIdForActiveBrowsingContextInContent == aOldActionId) {
5302 LOGFOCUS(("Revising the active BrowsingContext [%p]. old actionid: %" PRIu64do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Revising the active BrowsingContext [%p]. old actionid: %"
"l" "u" ", new " "actionid: %" "l" "u", aContext, aOldActionId
, aNewActionId); } } while (0)
5303 ", new "do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Revising the active BrowsingContext [%p]. old actionid: %"
"l" "u" ", new " "actionid: %" "l" "u", aContext, aOldActionId
, aNewActionId); } } while (0)
5304 "actionid: %" PRIu64,do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Revising the active BrowsingContext [%p]. old actionid: %"
"l" "u" ", new " "actionid: %" "l" "u", aContext, aOldActionId
, aNewActionId); } } while (0)
5305 aContext, aOldActionId, aNewActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Revising the active BrowsingContext [%p]. old actionid: %"
"l" "u" ", new " "actionid: %" "l" "u", aContext, aOldActionId
, aNewActionId); } } while (0)
;
5306 mActiveBrowsingContextInContent = aContext;
5307 mActionIdForActiveBrowsingContextInContent = aNewActionId;
5308 } else {
5309 LOGFOCUS(do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored a stale attempt to revise the active BrowsingContext [%p]. "
"old actionid: %" "l" "u" ", new actionid: %" "l" "u", aContext
, aOldActionId, aNewActionId); } } while (0)
5310 ("Ignored a stale attempt to revise the active BrowsingContext [%p]. "do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored a stale attempt to revise the active BrowsingContext [%p]. "
"old actionid: %" "l" "u" ", new actionid: %" "l" "u", aContext
, aOldActionId, aNewActionId); } } while (0)
5311 "old actionid: %" PRIu64 ", new actionid: %" PRIu64,do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored a stale attempt to revise the active BrowsingContext [%p]. "
"old actionid: %" "l" "u" ", new actionid: %" "l" "u", aContext
, aOldActionId, aNewActionId); } } while (0)
5312 aContext, aOldActionId, aNewActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored a stale attempt to revise the active BrowsingContext [%p]. "
"old actionid: %" "l" "u" ", new actionid: %" "l" "u", aContext
, aOldActionId, aNewActionId); } } while (0)
;
5313 }
5314}
5315
5316void nsFocusManager::ReviseFocusedBrowsingContext(
5317 uint64_t aOldActionId, mozilla::dom::BrowsingContext* aContext,
5318 uint64_t aNewActionId) {
5319 MOZ_ASSERT(XRE_IsContentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsContentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsContentProcess()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsContentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5319); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsContentProcess()"
")"); do { *((volatile int*)__null) = 5319; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5320 if (mActionIdForFocusedBrowsingContextInContent == aOldActionId) {
5321 LOGFOCUS(do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Revising the focused BrowsingContext [%p]. old actionid: %"
"l" "u" ", new " "actionid: %" "l" "u", aContext, aOldActionId
, aNewActionId); } } while (0)
5322 ("Revising the focused BrowsingContext [%p]. old actionid: %" PRIu64do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Revising the focused BrowsingContext [%p]. old actionid: %"
"l" "u" ", new " "actionid: %" "l" "u", aContext, aOldActionId
, aNewActionId); } } while (0)
5323 ", new "do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Revising the focused BrowsingContext [%p]. old actionid: %"
"l" "u" ", new " "actionid: %" "l" "u", aContext, aOldActionId
, aNewActionId); } } while (0)
5324 "actionid: %" PRIu64,do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Revising the focused BrowsingContext [%p]. old actionid: %"
"l" "u" ", new " "actionid: %" "l" "u", aContext, aOldActionId
, aNewActionId); } } while (0)
5325 aContext, aOldActionId, aNewActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Revising the focused BrowsingContext [%p]. old actionid: %"
"l" "u" ", new " "actionid: %" "l" "u", aContext, aOldActionId
, aNewActionId); } } while (0)
;
5326 mFocusedBrowsingContextInContent = aContext;
5327 mActionIdForFocusedBrowsingContextInContent = aNewActionId;
5328 mFocusedElement = nullptr;
5329 } else {
5330 LOGFOCUS(do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored a stale attempt to revise the focused BrowsingContext [%p]. "
"old actionid: %" "l" "u" ", new actionid: %" "l" "u", aContext
, aOldActionId, aNewActionId); } } while (0)
5331 ("Ignored a stale attempt to revise the focused BrowsingContext [%p]. "do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored a stale attempt to revise the focused BrowsingContext [%p]. "
"old actionid: %" "l" "u" ", new actionid: %" "l" "u", aContext
, aOldActionId, aNewActionId); } } while (0)
5332 "old actionid: %" PRIu64 ", new actionid: %" PRIu64,do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored a stale attempt to revise the focused BrowsingContext [%p]. "
"old actionid: %" "l" "u" ", new actionid: %" "l" "u", aContext
, aOldActionId, aNewActionId); } } while (0)
5333 aContext, aOldActionId, aNewActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored a stale attempt to revise the focused BrowsingContext [%p]. "
"old actionid: %" "l" "u" ", new actionid: %" "l" "u", aContext
, aOldActionId, aNewActionId); } } while (0)
;
5334 }
5335}
5336
5337bool nsFocusManager::SetActiveBrowsingContextInChrome(
5338 mozilla::dom::BrowsingContext* aContext, uint64_t aActionId) {
5339 MOZ_ASSERT(aActionId)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aActionId)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aActionId))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aActionId", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5339); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aActionId" ")"
); do { *((volatile int*)__null) = 5339; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5340 if (ProcessPendingActiveBrowsingContextActionId(aActionId, aContext)) {
5341 MOZ_DIAGNOSTIC_ASSERT(!ActionIdComparableAndLower(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!ActionIdComparableAndLower( aActionId, mActionIdForActiveBrowsingContextInChrome
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!ActionIdComparableAndLower( aActionId, mActionIdForActiveBrowsingContextInChrome
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!ActionIdComparableAndLower( aActionId, mActionIdForActiveBrowsingContextInChrome)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5342); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!ActionIdComparableAndLower( aActionId, mActionIdForActiveBrowsingContextInChrome)"
")"); do { *((volatile int*)__null) = 5342; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5342 aActionId, mActionIdForActiveBrowsingContextInChrome))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!ActionIdComparableAndLower( aActionId, mActionIdForActiveBrowsingContextInChrome
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!ActionIdComparableAndLower( aActionId, mActionIdForActiveBrowsingContextInChrome
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!ActionIdComparableAndLower( aActionId, mActionIdForActiveBrowsingContextInChrome)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5342); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "!ActionIdComparableAndLower( aActionId, mActionIdForActiveBrowsingContextInChrome)"
")"); do { *((volatile int*)__null) = 5342; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5343 mActiveBrowsingContextInChrome = aContext;
5344 mActionIdForActiveBrowsingContextInChrome = aActionId;
5345 return true;
5346 }
5347 return false;
5348}
5349
5350uint64_t nsFocusManager::GetActionIdForActiveBrowsingContextInChrome() const {
5351 return mActionIdForActiveBrowsingContextInChrome;
5352}
5353
5354uint64_t nsFocusManager::GetActionIdForFocusedBrowsingContextInChrome() const {
5355 return mActionIdForFocusedBrowsingContextInChrome;
5356}
5357
5358BrowsingContext* nsFocusManager::GetActiveBrowsingContextInChrome() {
5359 return mActiveBrowsingContextInChrome;
5360}
5361
5362void nsFocusManager::InsertNewFocusActionId(uint64_t aActionId) {
5363 LOGFOCUS(("InsertNewFocusActionId %" PRIu64, aActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "InsertNewFocusActionId %"
"l" "u", aActionId); } } while (0)
;
5364 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5364); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 5364; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5365 MOZ_ASSERT(!mPendingActiveBrowsingContextActions.Contains(aActionId))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mPendingActiveBrowsingContextActions.Contains(aActionId
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!mPendingActiveBrowsingContextActions.Contains(aActionId
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mPendingActiveBrowsingContextActions.Contains(aActionId)",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5365); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mPendingActiveBrowsingContextActions.Contains(aActionId)"
")"); do { *((volatile int*)__null) = 5365; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5366 mPendingActiveBrowsingContextActions.AppendElement(aActionId);
5367 MOZ_ASSERT(!mPendingFocusedBrowsingContextActions.Contains(aActionId))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mPendingFocusedBrowsingContextActions.Contains(aActionId
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!mPendingFocusedBrowsingContextActions.Contains(aActionId
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!mPendingFocusedBrowsingContextActions.Contains(aActionId)"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5367); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mPendingFocusedBrowsingContextActions.Contains(aActionId)"
")"); do { *((volatile int*)__null) = 5367; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5368 mPendingFocusedBrowsingContextActions.AppendElement(aActionId);
5369}
5370
5371static void RemoveContentInitiatedActionsUntil(
5372 nsTArray<uint64_t>& aPendingActions,
5373 nsTArray<uint64_t>::index_type aUntil) {
5374 nsTArray<uint64_t>::index_type i = 0;
5375 while (i < aUntil) {
5376 auto [actionProc, actionId] =
5377 nsContentUtils::SplitProcessSpecificId(aPendingActions[i]);
5378 Unused << actionId;
5379 if (actionProc) {
5380 aPendingActions.RemoveElementAt(i);
5381 --aUntil;
5382 continue;
5383 }
5384 ++i;
5385 }
5386}
5387
5388bool nsFocusManager::ProcessPendingActiveBrowsingContextActionId(
5389 uint64_t aActionId, bool aSettingToNonNull) {
5390 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5390); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 5390; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5391 auto index = mPendingActiveBrowsingContextActions.IndexOf(aActionId);
5392 if (index == nsTArray<uint64_t>::NoIndex) {
5393 return false;
5394 }
5395 // When aSettingToNonNull is true, we need to remove one more
5396 // element to remove the action id itself in addition to
5397 // removing the older ones.
5398 if (aSettingToNonNull) {
5399 index++;
5400 }
5401 auto [actionProc, actionId] =
5402 nsContentUtils::SplitProcessSpecificId(aActionId);
5403 Unused << actionId;
5404 if (actionProc) {
5405 // Action from content: We allow parent-initiated actions
5406 // to take precedence over content-initiated ones, so we
5407 // remove only prior content-initiated actions.
5408 RemoveContentInitiatedActionsUntil(mPendingActiveBrowsingContextActions,
5409 index);
5410 } else {
5411 // Action from chrome
5412 mPendingActiveBrowsingContextActions.RemoveElementsAt(0, index);
5413 }
5414 return true;
5415}
5416
5417bool nsFocusManager::ProcessPendingFocusedBrowsingContextActionId(
5418 uint64_t aActionId) {
5419 MOZ_ASSERT(XRE_IsParentProcess())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(XRE_IsParentProcess())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(XRE_IsParentProcess()))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("XRE_IsParentProcess()"
, "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5419); AnnotateMozCrashReason("MOZ_ASSERT" "(" "XRE_IsParentProcess()"
")"); do { *((volatile int*)__null) = 5419; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5420 auto index = mPendingFocusedBrowsingContextActions.IndexOf(aActionId);
5421 if (index == nsTArray<uint64_t>::NoIndex) {
5422 return false;
5423 }
5424
5425 auto [actionProc, actionId] =
5426 nsContentUtils::SplitProcessSpecificId(aActionId);
5427 Unused << actionId;
5428 if (actionProc) {
5429 // Action from content: We allow parent-initiated actions
5430 // to take precedence over content-initiated ones, so we
5431 // remove only prior content-initiated actions.
5432 RemoveContentInitiatedActionsUntil(mPendingFocusedBrowsingContextActions,
5433 index);
5434 } else {
5435 // Action from chrome
5436 mPendingFocusedBrowsingContextActions.RemoveElementsAt(0, index);
5437 }
5438 return true;
5439}
5440
5441// static
5442uint64_t nsFocusManager::GenerateFocusActionId() {
5443 uint64_t id =
5444 nsContentUtils::GenerateProcessSpecificId(++sFocusActionCounter);
5445 if (XRE_IsParentProcess()) {
5446 nsFocusManager* fm = GetFocusManager();
5447 if (fm) {
5448 fm->InsertNewFocusActionId(id);
5449 }
5450 } else {
5451 mozilla::dom::ContentChild* contentChild =
5452 mozilla::dom::ContentChild::GetSingleton();
5453 MOZ_ASSERT(contentChild)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(contentChild)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(contentChild))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("contentChild", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5453); AnnotateMozCrashReason("MOZ_ASSERT" "(" "contentChild"
")"); do { *((volatile int*)__null) = 5453; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5454 contentChild->SendInsertNewFocusActionId(id);
5455 }
5456 LOGFOCUS(("GenerateFocusActionId %" PRIu64, id))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "GenerateFocusActionId %"
"l" "u", id); } } while (0)
;
5457 return id;
5458}
5459
5460static bool IsInPointerLockContext(nsPIDOMWindowOuter* aWin) {
5461 return PointerLockManager::IsInLockContext(aWin ? aWin->GetBrowsingContext()
5462 : nullptr);
5463}
5464
5465void nsFocusManager::SetFocusedWindowInternal(nsPIDOMWindowOuter* aWindow,
5466 uint64_t aActionId,
5467 bool aSyncBrowsingContext) {
5468 if (XRE_IsParentProcess() && !PointerUnlocker::sActiveUnlocker &&
5469 IsInPointerLockContext(mFocusedWindow) &&
5470 !IsInPointerLockContext(aWindow)) {
5471 nsCOMPtr<nsIRunnable> runnable = new PointerUnlocker();
5472 NS_DispatchToCurrentThread(runnable);
5473 }
5474
5475 // Update the last focus time on any affected documents
5476 if (aWindow && aWindow != mFocusedWindow) {
5477 const TimeStamp now(TimeStamp::Now());
5478 for (Document* doc = aWindow->GetExtantDoc(); doc;
5479 doc = doc->GetInProcessParentDocument()) {
5480 doc->SetLastFocusTime(now);
5481 }
5482 }
5483
5484 // This function may be called with zero action id to indicate that the
5485 // action id should be ignored.
5486 if (XRE_IsContentProcess() && aActionId &&
5487 ActionIdComparableAndLower(aActionId,
5488 mActionIdForFocusedBrowsingContextInContent)) {
5489 // Unclear if this ever happens.
5490 LOGFOCUS(do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set an in-process BrowsingContext as "
"focused due to stale action id %" "l" "u" ".", aActionId); }
} while (0)
5491 ("Ignored an attempt to set an in-process BrowsingContext as "do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set an in-process BrowsingContext as "
"focused due to stale action id %" "l" "u" ".", aActionId); }
} while (0)
5492 "focused due to stale action id %" PRIu64 ".",do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set an in-process BrowsingContext as "
"focused due to stale action id %" "l" "u" ".", aActionId); }
} while (0)
5493 aActionId))do { const ::mozilla::LogModule* moz_real_module = gFocusLog;
if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Ignored an attempt to set an in-process BrowsingContext as "
"focused due to stale action id %" "l" "u" ".", aActionId); }
} while (0)
;
5494 return;
5495 }
5496
5497 mFocusedWindow = aWindow;
5498 BrowsingContext* bc = aWindow ? aWindow->GetBrowsingContext() : nullptr;
5499 if (aSyncBrowsingContext) {
5500 MOZ_ASSERT(aActionId,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aActionId)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aActionId))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aActionId" " (" "aActionId must not be zero if aSyncBrowsingContext is true"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5501); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aActionId" ") ("
"aActionId must not be zero if aSyncBrowsingContext is true"
")"); do { *((volatile int*)__null) = 5501; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5501 "aActionId must not be zero if aSyncBrowsingContext is true")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aActionId)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aActionId))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aActionId" " (" "aActionId must not be zero if aSyncBrowsingContext is true"
")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5501); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aActionId" ") ("
"aActionId must not be zero if aSyncBrowsingContext is true"
")"); do { *((volatile int*)__null) = 5501; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5502 SetFocusedBrowsingContext(bc, aActionId);
5503 } else if (XRE_IsContentProcess()) {
5504 MOZ_ASSERT(mFocusedBrowsingContextInContent == bc,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mFocusedBrowsingContextInContent == bc)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mFocusedBrowsingContextInContent == bc))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mFocusedBrowsingContextInContent == bc"
" (" "Not syncing BrowsingContext even when different." ")",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5505); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFocusedBrowsingContextInContent == bc"
") (" "Not syncing BrowsingContext even when different." ")"
); do { *((volatile int*)__null) = 5505; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5505 "Not syncing BrowsingContext even when different.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mFocusedBrowsingContextInContent == bc)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mFocusedBrowsingContextInContent == bc))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mFocusedBrowsingContextInContent == bc"
" (" "Not syncing BrowsingContext even when different." ")",
"/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5505); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFocusedBrowsingContextInContent == bc"
") (" "Not syncing BrowsingContext even when different." ")"
); do { *((volatile int*)__null) = 5505; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5506 }
5507}
5508
5509void nsFocusManager::NotifyOfReFocus(Element& aElement) {
5510 nsPIDOMWindowOuter* window = GetCurrentWindow(&aElement);
5511 if (!window || window != mFocusedWindow) {
5512 return;
5513 }
5514 if (!aElement.IsInComposedDoc() || IsNonFocusableRoot(&aElement)) {
5515 return;
5516 }
5517 nsIDocShell* docShell = window->GetDocShell();
5518 if (!docShell) {
5519 return;
5520 }
5521 RefPtr<PresShell> presShell = docShell->GetPresShell();
5522 if (!presShell) {
5523 return;
5524 }
5525 RefPtr<nsPresContext> presContext = presShell->GetPresContext();
5526 if (!presContext) {
5527 return;
5528 }
5529 IMEStateManager::OnReFocus(*presContext, aElement);
5530}
5531
5532void nsFocusManager::MarkUncollectableForCCGeneration(uint32_t aGeneration) {
5533 if (!sInstance) {
5534 return;
5535 }
5536
5537 if (sInstance->mActiveWindow) {
5538 sInstance->mActiveWindow->MarkUncollectableForCCGeneration(aGeneration);
5539 }
5540 if (sInstance->mFocusedWindow) {
5541 sInstance->mFocusedWindow->MarkUncollectableForCCGeneration(aGeneration);
5542 }
5543 if (sInstance->mWindowBeingLowered) {
5544 sInstance->mWindowBeingLowered->MarkUncollectableForCCGeneration(
5545 aGeneration);
5546 }
5547 if (sInstance->mFocusedElement) {
5548 sInstance->mFocusedElement->OwnerDoc()->MarkUncollectableForCCGeneration(
5549 aGeneration);
5550 }
5551 if (sInstance->mFirstBlurEvent) {
5552 sInstance->mFirstBlurEvent->OwnerDoc()->MarkUncollectableForCCGeneration(
5553 aGeneration);
5554 }
5555 if (sInstance->mFirstFocusEvent) {
5556 sInstance->mFirstFocusEvent->OwnerDoc()->MarkUncollectableForCCGeneration(
5557 aGeneration);
5558 }
5559}
5560
5561bool nsFocusManager::CanSkipFocus(nsIContent* aContent) {
5562 if (!aContent) {
5563 return false;
5564 }
5565
5566 if (mFocusedElement == aContent) {
5567 return true;
5568 }
5569
5570 nsIDocShell* ds = aContent->OwnerDoc()->GetDocShell();
5571 if (!ds) {
5572 return true;
5573 }
5574
5575 if (XRE_IsParentProcess()) {
5576 nsCOMPtr<nsIDocShellTreeItem> root;
5577 ds->GetInProcessRootTreeItem(getter_AddRefs(root));
5578 nsCOMPtr<nsPIDOMWindowOuter> newRootWindow =
5579 root ? root->GetWindow() : nullptr;
5580 if (mActiveWindow != newRootWindow) {
5581 nsPIDOMWindowOuter* outerWindow = aContent->OwnerDoc()->GetWindow();
5582 if (outerWindow && outerWindow->GetFocusedElement() == aContent) {
5583 return true;
5584 }
5585 }
5586 } else {
5587 BrowsingContext* bc = aContent->OwnerDoc()->GetBrowsingContext();
5588 BrowsingContext* top = bc ? bc->Top() : nullptr;
5589 if (GetActiveBrowsingContext() != top) {
5590 nsPIDOMWindowOuter* outerWindow = aContent->OwnerDoc()->GetWindow();
5591 if (outerWindow && outerWindow->GetFocusedElement() == aContent) {
5592 return true;
5593 }
5594 }
5595 }
5596
5597 return false;
5598}
5599
5600static IsFocusableFlags FocusManagerFlagsToIsFocusableFlags(uint32_t aFlags) {
5601 auto flags = IsFocusableFlags(0);
5602 if (aFlags & nsIFocusManager::FLAG_BYMOUSE) {
5603 flags |= IsFocusableFlags::WithMouse;
5604 }
5605 return flags;
5606}
5607
5608/* static */
5609Element* nsFocusManager::GetTheFocusableArea(Element* aTarget,
5610 uint32_t aFlags) {
5611 MOZ_ASSERT(aTarget)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTarget)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTarget))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aTarget", "/var/lib/jenkins/workspace/firefox-scan-build/dom/base/nsFocusManager.cpp"
, 5611); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aTarget" ")"
); do { *((volatile int*)__null) = 5611; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5612 nsIFrame* frame = aTarget->GetPrimaryFrame();
5613 if (!frame) {
5614 return nullptr;
5615 }
5616
5617 // If focus target is the document element of its Document.
5618 if (aTarget == aTarget->OwnerDoc()->GetRootElement()) {
5619 // the root content can always be focused,
5620 // except in userfocusignored context.
5621 return aTarget;
5622 }
5623
5624 // If focus target is an area element with one or more shapes that are
5625 // focusable areas.
5626 if (auto* area = HTMLAreaElement::FromNode(aTarget)) {
5627 return IsAreaElementFocusable(*area) ? area : nullptr;
5628 }
5629
5630 // For these 3 steps mentioned in the spec
5631 // 1. If focus target is an element with one or more scrollable regions that
5632 // are focusable areas
5633 // 2. If focus target is a navigable
5634 // 3. If focus target is a navigable container with a non-null content
5635 // navigable
5636 // nsIFrame::IsFocusable will effectively perform the checks for them.
5637 IsFocusableFlags flags = FocusManagerFlagsToIsFocusableFlags(aFlags);
5638 if (frame->IsFocusable(flags)) {
5639 return aTarget;
5640 }
5641
5642 // If focus target is a shadow host whose shadow root's delegates focus is
5643 // true
5644 if (ShadowRoot* root = aTarget->GetShadowRoot()) {
5645 if (root->DelegatesFocus()) {
5646 // If focus target is a shadow-including inclusive ancestor of the
5647 // currently focused area of a top-level browsing context's DOM anchor,
5648 // then return the already-focused element.
5649 if (nsPIDOMWindowInner* innerWindow =
5650 aTarget->OwnerDoc()->GetInnerWindow()) {
5651 if (Element* focusedElement = innerWindow->GetFocusedElement()) {
5652 if (focusedElement->IsShadowIncludingInclusiveDescendantOf(aTarget)) {
5653 return focusedElement;
5654 }
5655 }
5656 }
5657
5658 if (Element* firstFocusable = root->GetFocusDelegate(flags)) {
5659 return firstFocusable;
5660 }
5661 }
5662 }
5663 return nullptr;
5664}
5665
5666/* static */
5667bool nsFocusManager::IsAreaElementFocusable(HTMLAreaElement& aArea) {
5668 nsIFrame* frame = aArea.GetPrimaryFrame();
5669 if (!frame) {
5670 return false;
5671 }
5672 // HTML areas do not have their own frame, and the img frame we get from
5673 // GetPrimaryFrame() is not relevant as to whether it is focusable or
5674 // not, so we have to do all the relevant checks manually for them.
5675 return frame->IsVisibleConsideringAncestors() &&
5676 aArea.IsFocusableWithoutStyle();
5677}
5678
5679nsresult NS_NewFocusManager(nsIFocusManager** aResult) {
5680 NS_IF_ADDREF(*aResult = nsFocusManager::GetFocusManager())ns_if_addref(*aResult = nsFocusManager::GetFocusManager());
5681 return NS_OK;
5682}