tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 0c9992521b1f82785bf7c9d5136d152b483302d7
parent e8c7b719c8c02a5a6eb235cac6f7f6bde9e691cb
Author: Andreas Farre <farre@mozilla.com>
Date:   Wed,  5 Nov 2025 08:21:40 +0000

Bug 1997917 - Make sure to notify Navigation API about focus changes. r=smaug

Differential Revision: https://phabricator.services.mozilla.com/D271067

Diffstat:
Mdom/base/nsFocusManager.cpp | 21+++++++++++++++++++++
Mdom/events/NavigateEvent.cpp | 22++++++++++++++++++++--
Mdom/events/NavigateEvent.h | 1+
Mtesting/web-platform/meta/navigation-api/focus-reset/autofocus.html.ini | 9---------
Dtesting/web-platform/meta/navigation-api/focus-reset/basic.html.ini | 15---------------
Dtesting/web-platform/meta/navigation-api/focus-reset/focus-reset-timing.html.ini | 6------
Dtesting/web-platform/meta/navigation-api/focus-reset/multiple-intercept.html.ini | 9---------
7 files changed, 42 insertions(+), 41 deletions(-)

diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp @@ -39,6 +39,7 @@ #include "mozilla/dom/HTMLImageElement.h" #include "mozilla/dom/HTMLInputElement.h" #include "mozilla/dom/HTMLSlotElement.h" +#include "mozilla/dom/Navigation.h" #include "mozilla/dom/Selection.h" #include "mozilla/dom/Text.h" #include "mozilla/dom/WindowGlobalChild.h" @@ -913,6 +914,15 @@ void nsFocusManager::ContentAppended(nsIContent* aFirstNewContent, static void UpdateFocusWithinState(Element* aElement, nsIContent* aCommonAncestor, bool aGettingFocus) { + Element* focusedElement = nullptr; + Document* document = aElement->GetComposedDoc(); + if (aElement && document) { + if (nsPIDOMWindowOuter* window = document->GetWindow()) { + focusedElement = window->GetFocusedElement(); + } + } + + bool focusChanged = false; for (nsIContent* content = aElement; content && content != aCommonAncestor; content = content->GetFlattenedTreeParent()) { Element* element = Element::FromNode(content); @@ -924,10 +934,21 @@ static void UpdateFocusWithinState(Element* aElement, if (element->State().HasState(ElementState::FOCUS_WITHIN)) { break; } + element->AddStates(ElementState::FOCUS_WITHIN); } else { element->RemoveStates(ElementState::FOCUS_WITHIN); } + + focusChanged = focusChanged || element == focusedElement; + } + + if (focusChanged && document->GetInnerWindow()) { + if (RefPtr<Navigation> navigation = + document->GetInnerWindow()->Navigation()) { + navigation->SetFocusedChangedDuringOngoingNavigation( + /* aFocusChangedDuringOngoingNavigation */ true); + } } } diff --git a/dom/events/NavigateEvent.cpp b/dom/events/NavigateEvent.cpp @@ -15,6 +15,7 @@ #include "mozilla/dom/Navigation.h" #include "mozilla/dom/SessionHistoryEntry.h" #include "nsDocShell.h" +#include "nsFocusManager.h" #include "nsGlobalWindowInner.h" extern mozilla::LazyLogModule gNavigationAPILog; @@ -409,8 +410,25 @@ void NavigateEvent::PotentiallyResetFocus() { // Step 11, step 12 FocusOptions options; - LOG_FMT("Set focus for {}", *focusTarget->AsNode()); - focusTarget->Focus(options, CallerType::NonSystem, IgnoredErrorResult()); + options.mPreventScroll = true; + focusTarget = nsFocusManager::GetTheFocusableArea( + focusTarget, nsFocusManager::ProgrammaticFocusFlags(options)); + + if (focusTarget) { + LOG_FMT("Reset focus to {}", *focusTarget->AsNode()); + focusTarget->Focus(options, CallerType::NonSystem, IgnoredErrorResult()); + } else if (RefPtr<nsIFocusManager> focusManager = + nsFocusManager::GetFocusManager()) { + if (nsPIDOMWindowOuter* window = document->GetWindow()) { + // Now focus the document itself if focus is on an element within it. + nsCOMPtr<mozIDOMWindowProxy> focusedWindow; + focusManager->GetFocusedWindow(getter_AddRefs(focusedWindow)); + if (SameCOMIdentity(window, focusedWindow)) { + LOG_FMT("Reset focus to document viewport"); + focusManager->ClearFocus(focusedWindow); + } + } + } } // https://html.spec.whatwg.org/#potentially-process-scroll-behavior diff --git a/dom/events/NavigateEvent.h b/dom/events/NavigateEvent.h @@ -117,6 +117,7 @@ class NavigateEvent final : public Event { void PerformSharedChecks(ErrorResult& aRv); private: + MOZ_CAN_RUN_SCRIPT void PotentiallyResetFocus(); MOZ_CAN_RUN_SCRIPT diff --git a/testing/web-platform/meta/navigation-api/focus-reset/autofocus.html.ini b/testing/web-platform/meta/navigation-api/focus-reset/autofocus.html.ini @@ -1,12 +1,3 @@ [autofocus.html] - [An element with autofocus, present before navigation but disabled before finished, does not get focused] - expected: FAIL - - [An element with autofocus, present before navigation but with its autofocus attribute removed before finished, does not get focused] - expected: FAIL - [An element with autofocus, introduced between committed and finished, gets focused] expected: FAIL - - [An element with autofocus, introduced after finished, does not get focused] - expected: FAIL diff --git a/testing/web-platform/meta/navigation-api/focus-reset/basic.html.ini b/testing/web-platform/meta/navigation-api/focus-reset/basic.html.ini @@ -1,15 +0,0 @@ -[basic.html] - [Resets the focus when no focusReset option is provided] - expected: FAIL - - [Resets the focus when focusReset is explicitly set to undefined] - expected: FAIL - - [Resets the focus when no focusReset option is provided (nontrivial fulfilled promise)] - expected: FAIL - - [Resets the focus when no focusReset option is provided (rejected promise)] - expected: FAIL - - [Resets the focus when focusReset is explicitly set to 'after-transition'] - expected: FAIL diff --git a/testing/web-platform/meta/navigation-api/focus-reset/focus-reset-timing.html.ini b/testing/web-platform/meta/navigation-api/focus-reset/focus-reset-timing.html.ini @@ -1,6 +0,0 @@ -[focus-reset-timing.html] - [Focus should be reset before navigatesuccess] - expected: FAIL - - [Focus should be reset before navigateerror] - expected: FAIL diff --git a/testing/web-platform/meta/navigation-api/focus-reset/multiple-intercept.html.ini b/testing/web-platform/meta/navigation-api/focus-reset/multiple-intercept.html.ini @@ -1,9 +0,0 @@ -[multiple-intercept.html] - [(not provided) + after-transition] - expected: FAIL - - [after-transition + (not provided)] - expected: FAIL - - [manual + after-transition] - expected: FAIL