Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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