--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -532,20 +532,18 @@ nsFocusManager::MoveFocus(mozIDOMWindowP
nsCOMPtr<nsPIDOMWindowOuter> window;
nsCOMPtr<nsIContent> startContent;
if (aStartElement) {
startContent = do_QueryInterface(aStartElement);
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);
bool noParentTraversal = aFlags & FLAG_NOPARENTFRAME;
nsCOMPtr<nsIContent> newFocus;
nsresult rv = DetermineElementToMoveFocus(window, startContent, aType, noParentTraversal,
getter_AddRefs(newFocus));
@@ -860,17 +858,17 @@ nsFocusManager::ContentRemoved(nsIDocume
if (limiter == content) {
editor->FinalizeSelection();
}
}
}
}
}
- NotifyFocusStateChange(content, shouldShowFocusRing, false);
+ NotifyFocusStateChange(content, nullptr, shouldShowFocusRing, false);
}
return NS_OK;
}
NS_IMETHODIMP
nsFocusManager::WindowShown(mozIDOMWindowProxy* aWindow, bool aNeedsFocus)
{
@@ -966,16 +964,17 @@ nsFocusManager::WindowHidden(mozIDOMWind
nsCOMPtr<nsIContent> oldFocusedContent = mFocusedContent.forget();
nsCOMPtr<nsIDocShell> focusedDocShell = mFocusedWindow->GetDocShell();
nsCOMPtr<nsIPresShell> presShell = focusedDocShell->GetPresShell();
if (oldFocusedContent && oldFocusedContent->IsInComposedDoc()) {
NotifyFocusStateChange(oldFocusedContent,
+ nullptr,
mFocusedWindow->ShouldShowFocusRing(),
false);
window->UpdateCommands(NS_LITERAL_STRING("focus"), nullptr, 0);
if (presShell) {
SendFocusOrBlurEvent(eBlur, presShell,
oldFocusedContent->GetComposedDoc(),
oldFocusedContent, 1, false);
@@ -1085,36 +1084,54 @@ nsFocusManager::ParentActivated(mozIDOMW
ActivateOrDeactivate(window, aActive);
return NS_OK;
}
/* 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;
}
if (aGettingFocus) {
aContent->AsElement()->AddStates(eventState);
} else {
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);
}
}
}
// static
@@ -1658,17 +1675,20 @@ nsFocusManager::Blur(nsPIDOMWindowOuter*
LOGCONTENT("Element %s has been blurred", content.get());
// Don't fire blur event on the root content which isn't editable.
bool sendBlurEvent =
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
// to the parent window, otherwise events will still get fired at the plugin.
// But don't do this if we are blurring due to the window being lowered,
// otherwise, the parent window can get raised again.
if (mActiveWindow) {
nsIFrame* contentFrame = content->GetPrimaryFrame();
@@ -1909,17 +1929,20 @@ nsFocusManager::Focus(nsPIDOMWindowOuter
if (aContent && aFocusChanged) {
ScrollIntoView(presShell, aContent, aFlags);
}
bool sendFocusEvent =
aContent && aContent->IsInComposedDoc() && !IsNonFocusableRoot(aContent);
nsPresContext* presContext = presShell->GetPresContext();
if (sendFocusEvent) {
- 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
// aIsNewDocument.
if (presShell->GetDocument() == aContent->GetComposedDoc()) {
if (aAdjustWidgets && objectFrameWidget && !sTestMode)
objectFrameWidget->SetFocus(false);
--- a/dom/base/nsFocusManager.h
+++ b/dom/base/nsFocusManager.h
@@ -510,16 +510,17 @@ private:
// we need to pass in whether the window should show a focus ring
// before the SetFocusedNode call on it happened when losing focus
// and after the SetFocusedNode call when gaining focus, which is
// why that information needs to be an explicit argument instead of
// just passing in the window and asking it whether it should show
// focus rings: in the losing focus case that information could be
// wrong..
static void NotifyFocusStateChange(nsIContent* aContent,
+ nsIContent* aContentToFocus,
bool aWindowShouldShowFocusRing,
bool aGettingFocus);
void SetFocusedWindowInternal(nsPIDOMWindowOuter* aWindow);
// Notify the change of content window ID
// belonging to the top level outer window.
void NotifyCurrentTopLevelContentWindowChange(nsPIDOMWindowOuter* aWindow);