Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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