diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp index a0e162b0a1..fa321ac300 100644 --- a/dom/base/nsFocusManager.cpp +++ b/dom/base/nsFocusManager.cpp @@ -538,10 +538,8 @@ nsFocusManager::MoveFocus(mozIDOMWindowProxy* aWindow, nsIDOMElement* aStartElem NS_ENSURE_TRUE(startContent, NS_ERROR_INVALID_ARG); window = GetCurrentWindow(startContent); - } - else { + } else { window = aWindow ? nsPIDOMWindowOuter::From(aWindow) : mFocusedWindow.get(); - 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; @@ -973,6 +971,7 @@ nsFocusManager::WindowHidden(mozIDOMWindowProxy* aWindow) if (oldFocusedContent && oldFocusedContent->IsInComposedDoc()) { NotifyFocusStateChange(oldFocusedContent, + nullptr, mFocusedWindow->ShouldShowFocusRing(), false); window->UpdateCommands(NS_LITERAL_STRING("focus"), nullptr, 0); @@ -1091,12 +1090,21 @@ nsFocusManager::ParentActivated(mozIDOMWindowProxy* aWindow, bool aActive) /* static */ void nsFocusManager::NotifyFocusStateChange(nsIContent* aContent, + nsIContent* aContentToFocus, bool aWindowShouldShowFocusRing, bool aGettingFocus) { + MOZ_ASSERT_IF(aContentToFocus, !aGettingFocus); if (!aContent->IsElement()) { return; } + + nsIContent* commonAncestor = nullptr; + if (aContentToFocus && aContentToFocus->IsElement()) { + commonAncestor = + nsContentUtils::GetCommonFlattenedTreeAncestor(aContent, aContentToFocus); + } + EventStates eventState = NS_EVENT_STATE_FOCUS; if (aWindowShouldShowFocusRing) { eventState |= NS_EVENT_STATE_FOCUSRING; @@ -1108,9 +1116,18 @@ nsFocusManager::NotifyFocusStateChange(nsIContent* aContent, aContent->AsElement()->RemoveStates(eventState); } - for (Element* element = aContent->AsElement(); element; - element = element->GetParentElementCrossingShadowRoot()) { + for (nsIContent* content = aContent; + content && content != commonAncestor; + content = content->GetFlattenedTreeParent()) { + if (!content->IsElement()) { + continue; + } + + Element* element = content->AsElement(); if (aGettingFocus) { + if (element->State().HasState(NS_EVENT_STATE_FOCUS_WITHIN)) { + break; + } element->AddStates(NS_EVENT_STATE_FOCUS_WITHIN); } else { element->RemoveStates(NS_EVENT_STATE_FOCUS_WITHIN); @@ -1673,7 +1690,10 @@ nsFocusManager::Blur(nsPIDOMWindowOuter* aWindowToClear, content && content->IsInComposedDoc() && !IsNonFocusableRoot(content); if (content) { 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 @@ -1921,7 +1941,10 @@ nsFocusManager::Focus(nsPIDOMWindowOuter* aWindow, if (aFocusChanged) 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 // no longer be in the same document, due to the events we fired above when diff --git a/dom/base/nsFocusManager.h b/dom/base/nsFocusManager.h index c98b092468..8fe919a155 100644 --- a/dom/base/nsFocusManager.h +++ b/dom/base/nsFocusManager.h @@ -583,6 +583,7 @@ private: // focus rings: in the losing focus case that information could be // wrong.. static void NotifyFocusStateChange(nsIContent* aContent, + nsIContent* aContentToFocus, bool aWindowShouldShowFocusRing, bool aGettingFocus);