tor-browser

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

commit 64683992ff9726072627514179101359e6876d67
parent 7a3fd8df5061232e9d7e78acb1b5703da40e17cd
Author: Alexandru Marc <amarc@mozilla.com>
Date:   Mon, 27 Oct 2025 19:08:14 +0200

Revert "Bug 1996182 - Fix up focus within state on focus redirect as well. r=smaug" for causing mochitest failures @ HTMLEditor.cpp

This reverts commit 6a2fbb9803ba82a9bcb1dcb64e96556b9e55fae7.

Revert "Bug 1996182 - Clear stale focus-within state from ContentRemoved. r=smaug"

This reverts commit 99b320901a54318b2fb25abaad74a79678d09fac.

Diffstat:
Mdom/base/nsFocusManager.cpp | 96++++++++++++++++++++++---------------------------------------------------------
Dtesting/web-platform/tests/css/selectors/focus-within-focus-move.html | 37-------------------------------------
Dtesting/web-platform/tests/css/selectors/focus-within-removal.html | 36------------------------------------
3 files changed, 26 insertions(+), 143 deletions(-)

diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp @@ -8,7 +8,6 @@ #include <algorithm> -#include "AncestorIterator.h" #include "BrowserChild.h" #include "ChildIterator.h" #include "ContentParent.h" @@ -911,45 +910,6 @@ void nsFocusManager::ContentAppended(nsIContent* aFirstNewContent, FocusedElementMayHaveMoved(aFirstNewContent, aInfo.mOldParent); } -static void UpdateFocusWithinState(Element* aElement, - nsIContent* aCommonAncestor, - bool aGettingFocus) { - for (nsIContent* content = aElement; content && content != aCommonAncestor; - content = content->GetFlattenedTreeParent()) { - Element* element = Element::FromNode(content); - if (!element) { - continue; - } - - if (aGettingFocus) { - if (element->State().HasState(ElementState::FOCUS_WITHIN)) { - break; - } - element->AddStates(ElementState::FOCUS_WITHIN); - } else { - element->RemoveStates(ElementState::FOCUS_WITHIN); - } - } -} - -static void MaybeFixUpFocusWithinState(Element* aElementToFocus, - Element* aFocusedElement) { - if (!aElementToFocus || aElementToFocus == aFocusedElement || - !aElementToFocus->IsInComposedDoc()) { - return; - } - // Focus was redirected, make sure the :focus-within state remains consistent. - auto* commonAncestor = [&]() -> nsIContent* { - if (!aFocusedElement || - aElementToFocus->OwnerDoc() != aFocusedElement->OwnerDoc()) { - return nullptr; - } - return nsContentUtils::GetCommonFlattenedTreeAncestor(aFocusedElement, - aElementToFocus); - }(); - UpdateFocusWithinState(aElementToFocus, commonAncestor, false); -} - nsresult nsFocusManager::ContentRemoved(Document* aDocument, nsIContent* aContent, const ContentRemoveInfo& aInfo) { @@ -966,37 +926,22 @@ nsresult nsFocusManager::ContentRemoved(Document* aDocument, return NS_OK; } - Element* focusWithinElement = [&]() -> Element* { - if (auto* el = Element::FromNode(aContent)) { - return el; - } - if (auto* shadow = ShadowRoot::FromNode(aContent)) { - // Note that we only get here with ShadowRoots for shadow roots of form - // controls that we can un-attach. So if there's a focused element it must - // be inside our shadow tree already. - return shadow->Host(); - } - // Removing text / comments / etc can't affect the focus state. - return nullptr; - }(); - if (!focusWithinElement || - !focusWithinElement->State().HasAtLeastOneOfStates( - ElementState::FOCUS | ElementState::FOCUS_WITHIN)) { - return NS_OK; - } - // if the content is currently focused in the window, or is an // shadow-including inclusive ancestor of the currently focused element, // reset the focus within that window. - RefPtr previousFocusedElement = windowPtr->GetFocusedElement(); - if (!previousFocusedElement) { - // If we're in-between a blur and an incoming focus, we might have stale - // :focus-within in our ancestor chain. Fix it up now. - UpdateFocusWithinState(focusWithinElement, nullptr, false); + Element* previousFocusedElementPtr = windowPtr->GetFocusedElement(); + if (!previousFocusedElementPtr) { + return NS_OK; + } + + if (!nsContentUtils::ContentIsHostIncludingDescendantOf( + previousFocusedElementPtr, aContent)) { return NS_OK; } RefPtr<nsPIDOMWindowOuter> window = windowPtr; + RefPtr<Element> previousFocusedElement = previousFocusedElementPtr; + RefPtr<Element> newFocusedElement = [&]() -> Element* { if (auto* sr = ShadowRoot::FromNode(aContent)) { if (sr->IsUAWidget() && sr->Host()->IsHTMLElement(nsGkAtoms::input)) { @@ -1069,7 +1014,7 @@ nsresult nsFocusManager::ContentRemoved(Document* aDocument, } if (!newFocusedElement) { - NotifyFocusStateChange(previousFocusedElement, nullptr, 0, + NotifyFocusStateChange(previousFocusedElement, newFocusedElement, 0, /* aGettingFocus = */ false, false); } else { // We should already have the right state, which is managed by the <input> @@ -1511,7 +1456,22 @@ void nsFocusManager::NotifyFocusStateChange(Element* aElement, } } - UpdateFocusWithinState(aElement, commonAncestor, aGettingFocus); + for (nsIContent* content = aElement; content && content != commonAncestor; + content = content->GetFlattenedTreeParent()) { + Element* element = Element::FromNode(content); + if (!element) { + continue; + } + + if (aGettingFocus) { + if (element->State().HasState(ElementState::FOCUS_WITHIN)) { + break; + } + element->AddStates(ElementState::FOCUS_WITHIN); + } else { + element->RemoveStates(ElementState::FOCUS_WITHIN); + } + } } // static @@ -1917,7 +1877,6 @@ Maybe<uint64_t> nsFocusManager::SetFocusInner(Element* aNewContent, : nullptr), commonAncestor, focusMovesToDifferentBC, aAdjustWidget, remainActive, actionId, elementToFocus)) { - MaybeFixUpFocusWithinState(elementToFocus, mFocusedElement); return Some(actionId); } } @@ -2869,9 +2828,6 @@ void nsFocusManager::Focus( } } } else { - // We only need this on this branch, on the branch above - // NotifyFocusStateChange takes care of it. - MaybeFixUpFocusWithinState(elementToFocus, mFocusedElement); if (!mFocusedElement && mFocusedWindow == aWindow) { // When there is no focused element, IMEStateManager needs to adjust IME // enabled state with the document. diff --git a/testing/web-platform/tests/css/selectors/focus-within-focus-move.html b/testing/web-platform/tests/css/selectors/focus-within-focus-move.html @@ -1,37 +0,0 @@ -<!doctype html> -<meta charset="utf-8"> -<title>Moving focus from its own focus() call doesn't leave stale :focus-within state</title> -<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-focus-within-pseudo"> -<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1996182"> -<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez"> -<link rel="author" href="https://mozilla.com" title="Mozilla"> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<div id="wrapper"> - <div id="outer"> - <input id="tab"> - <input id="input" onblur="outside.focus()"> - </div> - <input id="outside"> -</div> -<script> -onload = function() { - test(function() { - let wrapper = document.getElementById("wrapper"); - let outer = document.getElementById("outer"); - let tab = document.getElementById("tab"); - let input = document.getElementById("input"); - let outside = document.getElementById("outside"); - - input.focus(); - assert_equals(document.activeElement, input, "activeElement after focus"); - assert_true(outer.matches(":focus-within"), "outer matches :focus-within"); - assert_true(wrapper.matches(":focus-within"), "wrapper matches :focus-within"); - // This ends up shifting to `outside` rather than `tab`. - tab.focus(); - assert_equals(document.activeElement, outside, "activeElement after trying to focus sibling"); - assert_true(wrapper.matches(":focus-within"), "wrapper still matches :focus-within"); - assert_false(outer.matches(":focus-within"), "outer no longer matches :focus-within"); - }); -} -</script> diff --git a/testing/web-platform/tests/css/selectors/focus-within-removal.html b/testing/web-platform/tests/css/selectors/focus-within-removal.html @@ -1,36 +0,0 @@ -<!doctype html> -<meta charset="utf-8"> -<title>Removing an element from its own focus() call doesn't leave stale :focus-within state</title> -<link rel="help" href="https://drafts.csswg.org/selectors-4/#the-focus-within-pseudo"> -<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1996182"> -<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez"> -<link rel="author" href="https://mozilla.com" title="Mozilla"> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<div id="root"> - <div id="container" tabindex="-1"> - <input type="text"> - </div> -</div> -<script> -onload = function() { - test(function() { - let root = document.getElementById("root"); - let container = document.getElementById("container"); - let input = document.querySelector("input"); - - input.focus(); - assert_equals(document.activeElement, input, "activeElement after focus"); - assert_true(container.matches(":focus-within"), "container matches :focus-within"); - assert_true(root.matches(":focus-within"), "root also matches :focus-within"); - // This fires from within the next focus() call - input.addEventListener("focusout", () => { root.innerHTML = "" }); - // container is focusable, but gets removed before we get a chance at focusing it. - container.focus(); - assert_equals(document.activeElement, document.body, "activeElement after trying to focus sibling"); - assert_equals(container.parentNode, null, "container should get removed"); - assert_false(container.matches(":focus-within"), "container no longer matches :focus-within"); - assert_false(root.matches(":focus-within"), "root no longer matches :focus-within"); - }); -} -</script>