Issue #2401 - Part 3: Don't toggle focus-within state past the nearest common flattened tree ancestor.

Resolves #2401
This commit is contained in:
Moonchild 2024-01-09 18:23:47 +01:00 • committed by roytam1
commit bd723aac28
2 changed files with 32 additions and 8 deletions

View file

@ -538,10 +538,8 @@ nsFocusManager::MoveFocus(mozIDOMWindowProxy* aWindow, nsIDOMElement* aStartElem
NS_ENSURE_TRUE(startContent, NS_ERROR_INVALID_ARG); NS_ENSURE_TRUE(startContent, NS_ERROR_INVALID_ARG);
window = GetCurrentWindow(startContent); window = GetCurrentWindow(startContent);
} } else {
else {
window = aWindow ? nsPIDOMWindowOuter::From(aWindow) : mFocusedWindow.get(); window = aWindow ? nsPIDOMWindowOuter::From(aWindow) : mFocusedWindow.get();
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
} }
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
@ -867,7 +865,7 @@ nsFocusManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent)
} }
} }
NotifyFocusStateChange(content, shouldShowFocusRing, false); NotifyFocusStateChange(content, nullptr, shouldShowFocusRing, false);
} }
return NS_OK; return NS_OK;
@ -973,6 +971,7 @@ nsFocusManager::WindowHidden(mozIDOMWindowProxy* aWindow)
if (oldFocusedContent && oldFocusedContent->IsInComposedDoc()) { if (oldFocusedContent && oldFocusedContent->IsInComposedDoc()) {
NotifyFocusStateChange(oldFocusedContent, NotifyFocusStateChange(oldFocusedContent,
nullptr,
mFocusedWindow->ShouldShowFocusRing(), mFocusedWindow->ShouldShowFocusRing(),
false); false);
window->UpdateCommands(NS_LITERAL_STRING("focus"), nullptr, 0); window->UpdateCommands(NS_LITERAL_STRING("focus"), nullptr, 0);
@ -1091,12 +1090,21 @@ nsFocusManager::ParentActivated(mozIDOMWindowProxy* aWindow, bool aActive)
/* static */ /* static */
void void
nsFocusManager::NotifyFocusStateChange(nsIContent* aContent, nsFocusManager::NotifyFocusStateChange(nsIContent* aContent,
nsIContent* aContentToFocus,
bool aWindowShouldShowFocusRing, bool aWindowShouldShowFocusRing,
bool aGettingFocus) bool aGettingFocus)
{ {
MOZ_ASSERT_IF(aContentToFocus, !aGettingFocus);
if (!aContent->IsElement()) { if (!aContent->IsElement()) {
return; return;
} }
nsIContent* commonAncestor = nullptr;
if (aContentToFocus && aContentToFocus->IsElement()) {
commonAncestor =
nsContentUtils::GetCommonFlattenedTreeAncestor(aContent, aContentToFocus);
}
EventStates eventState = NS_EVENT_STATE_FOCUS; EventStates eventState = NS_EVENT_STATE_FOCUS;
if (aWindowShouldShowFocusRing) { if (aWindowShouldShowFocusRing) {
eventState |= NS_EVENT_STATE_FOCUSRING; eventState |= NS_EVENT_STATE_FOCUSRING;
@ -1108,9 +1116,18 @@ nsFocusManager::NotifyFocusStateChange(nsIContent* aContent,
aContent->AsElement()->RemoveStates(eventState); aContent->AsElement()->RemoveStates(eventState);
} }
for (Element* element = aContent->AsElement(); element; for (nsIContent* content = aContent;
element = element->GetParentElementCrossingShadowRoot()) { content && content != commonAncestor;
content = content->GetFlattenedTreeParent()) {
if (!content->IsElement()) {
continue;
}
Element* element = content->AsElement();
if (aGettingFocus) { if (aGettingFocus) {
if (element->State().HasState(NS_EVENT_STATE_FOCUS_WITHIN)) {
break;
}
element->AddStates(NS_EVENT_STATE_FOCUS_WITHIN); element->AddStates(NS_EVENT_STATE_FOCUS_WITHIN);
} else { } else {
element->RemoveStates(NS_EVENT_STATE_FOCUS_WITHIN); element->RemoveStates(NS_EVENT_STATE_FOCUS_WITHIN);
@ -1673,7 +1690,10 @@ nsFocusManager::Blur(nsPIDOMWindowOuter* aWindowToClear,
content && content->IsInComposedDoc() && !IsNonFocusableRoot(content); content && content->IsInComposedDoc() && !IsNonFocusableRoot(content);
if (content) { if (content) {
if (sendBlurEvent) { if (sendBlurEvent) {
NotifyFocusStateChange(content, shouldShowFocusRing, false); NotifyFocusStateChange(content,
aContentToFocus,
shouldShowFocusRing,
false);
} }
// if an object/plug-in/remote browser is being blurred, move the system focus // if an object/plug-in/remote browser is being blurred, move the system focus
@ -1921,7 +1941,10 @@ nsFocusManager::Focus(nsPIDOMWindowOuter* aWindow,
if (aFocusChanged) if (aFocusChanged)
ScrollIntoView(presShell, aContent, aFlags); ScrollIntoView(presShell, aContent, aFlags);
NotifyFocusStateChange(aContent, aWindow->ShouldShowFocusRing(), true); NotifyFocusStateChange(aContent,
nullptr,
aWindow->ShouldShowFocusRing(),
true);
// if this is an object/plug-in/remote browser, focus its widget. Note that we might // if this is an object/plug-in/remote browser, focus its widget. Note that we might
// no longer be in the same document, due to the events we fired above when // no longer be in the same document, due to the events we fired above when

View file

@ -583,6 +583,7 @@ private:
// focus rings: in the losing focus case that information could be // focus rings: in the losing focus case that information could be
// wrong.. // wrong..
static void NotifyFocusStateChange(nsIContent* aContent, static void NotifyFocusStateChange(nsIContent* aContent,
nsIContent* aContentToFocus,
bool aWindowShouldShowFocusRing, bool aWindowShouldShowFocusRing,
bool aGettingFocus); bool aGettingFocus);