Bug Summary

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