Bug 598833 part 5. Store focus and focusring state directly on elements. r=smaug,enn

This commit is contained in:
Boris Zbarsky 2011-05-31 21:46:56 -04:00
Родитель c45aba531e
Коммит ace23ff3cb
5 изменённых файлов: 59 добавлений и 42 удалений

Просмотреть файл

@ -44,6 +44,8 @@
#include "nsEventStates.h"
class nsEventStateManager;
class nsGlobalWindow;
class nsFocusManager;
// Element-specific flags
enum {
@ -107,8 +109,11 @@ public:
}
private:
// Need to allow the ESM to set our state
// Need to allow the ESM, nsGlobalWindow, and the focus manager to
// set our state
friend class ::nsEventStateManager;
friend class ::nsGlobalWindow;
friend class ::nsFocusManager;
void NotifyStateChange(nsEventStates aStates);

Просмотреть файл

@ -4211,18 +4211,6 @@ GetLabelTarget(nsIContent* aPossibleLabel)
return label->GetLabeledElement();
}
static bool
ShouldShowFocusRing(nsIContent* aContent)
{
nsIDocument* doc = aContent->GetOwnerDoc();
if (doc) {
nsPIDOMWindow* window = doc->GetWindow();
return window && window->ShouldShowFocusRing();
}
return false;
}
nsEventStates
nsEventStateManager::GetContentState(nsIContent *aContent)
{
@ -4231,15 +4219,6 @@ nsEventStateManager::GetContentState(nsIContent *aContent)
state = aContent->AsElement()->State();
}
nsFocusManager* fm = nsFocusManager::GetFocusManager();
nsIContent* focusedContent = fm ? fm->GetFocusedContent() : nsnull;
if (aContent == focusedContent) {
state |= NS_EVENT_STATE_FOCUS;
if (ShouldShowFocusRing(aContent)) {
state |= NS_EVENT_STATE_FOCUSRING;
}
}
return state;
}

Просмотреть файл

@ -803,6 +803,7 @@ nsFocusManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent)
// of the currently focused element, reset the focus within that window.
nsIContent* content = window->GetFocusedNode();
if (content && nsContentUtils::ContentIsDescendantOf(content, aContent)) {
PRBool shouldShowFocusRing = window->ShouldShowFocusRing();
window->SetFocusedNode(nsnull);
nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
@ -832,6 +833,8 @@ nsFocusManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent)
}
}
}
NotifyFocusStateChange(aContent, shouldShowFocusRing, PR_FALSE);
}
return NS_OK;
@ -884,18 +887,6 @@ nsFocusManager::WindowShown(nsIDOMWindow* aWindow, PRBool aNeedsFocus)
return NS_OK;
}
static void
NotifyFocusStateChange(nsIContent* aContent, nsPIDOMWindow* aWindow)
{
nsIDocument *doc = aContent->GetCurrentDoc();
nsAutoScriptBlocker scriptBlocker;
nsEventStates eventState = NS_EVENT_STATE_FOCUS;
if (aWindow->ShouldShowFocusRing()) {
eventState |= NS_EVENT_STATE_FOCUSRING;
}
doc->ContentStateChanged(aContent, eventState);
}
NS_IMETHODIMP
nsFocusManager::WindowHidden(nsIDOMWindow* aWindow)
{
@ -946,7 +937,9 @@ nsFocusManager::WindowHidden(nsIDOMWindow* aWindow)
mFocusedContent = nsnull;
if (oldFocusedContent && oldFocusedContent->IsInDoc()) {
NotifyFocusStateChange(oldFocusedContent, mFocusedWindow);
NotifyFocusStateChange(oldFocusedContent,
mFocusedWindow->ShouldShowFocusRing(),
PR_FALSE);
}
nsCOMPtr<nsIDocShell> focusedDocShell = mFocusedWindow->GetDocShell();
@ -1033,6 +1026,26 @@ nsFocusManager::FocusPlugin(nsIContent* aContent)
return NS_OK;
}
/* static */
void
nsFocusManager::NotifyFocusStateChange(nsIContent* aContent,
PRBool aWindowShouldShowFocusRing,
PRBool aGettingFocus)
{
if (!aContent->IsElement()) {
return;
}
nsEventStates eventState = NS_EVENT_STATE_FOCUS;
if (aWindowShouldShowFocusRing) {
eventState |= NS_EVENT_STATE_FOCUSRING;
}
if (aGettingFocus) {
aContent->AsElement()->AddStates(eventState);
} else {
aContent->AsElement()->RemoveStates(eventState);
}
}
// static
void
nsFocusManager::EnsureCurrentWidgetFocused()
@ -1501,6 +1514,7 @@ nsFocusManager::Blur(nsPIDOMWindow* aWindowToClear,
// now adjust the actual focus, by clearing the fields in the focus manager
// and in the window.
mFocusedContent = nsnull;
PRBool shouldShowFocusRing = window->ShouldShowFocusRing();
if (aWindowToClear)
aWindowToClear->SetFocusedNode(nsnull);
@ -1513,7 +1527,7 @@ nsFocusManager::Blur(nsPIDOMWindow* aWindowToClear,
content && content->IsInDoc() && !IsNonFocusableRoot(content);
if (content) {
if (sendBlurEvent) {
NotifyFocusStateChange(content, window);
NotifyFocusStateChange(content, shouldShowFocusRing, PR_FALSE);
}
// if an object/plug-in is being blurred, move the system focus to the
@ -1729,7 +1743,7 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow,
if (aFocusChanged)
ScrollIntoView(presShell, aContent, aFlags);
NotifyFocusStateChange(aContent, aWindow);
NotifyFocusStateChange(aContent, aWindow->ShouldShowFocusRing(), PR_TRUE);
// if this is an object/plug-in, focus the plugin's widget. Note that we might
// no longer be in the same document, due to the events we fired above when

Просмотреть файл

@ -467,6 +467,19 @@ protected:
nsIContent* aEndSelection,
nsIContent** aFocusedContent);
private:
// Notify that the focus state of aContent has changed. Note that
// 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,
PRBool aWindowShouldShowFocusRing,
PRBool aGettingFocus);
// the currently active and front-most top-most window
nsCOMPtr<nsPIDOMWindow> mActiveWindow;

Просмотреть файл

@ -7653,6 +7653,8 @@ nsGlobalWindow::SetKeyboardIndicators(UIStateChangeType aShowAccelerators,
{
FORWARD_TO_INNER_VOID(SetKeyboardIndicators, (aShowAccelerators, aShowFocusRings));
PRBool oldShouldShowFocusRing = ShouldShowFocusRing();
// only change the flags that have been modified
if (aShowAccelerators != UIStateChangeType_NoChange)
mShowAccelerators = aShowAccelerators == UIStateChangeType_Set;
@ -7675,11 +7677,15 @@ nsGlobalWindow::SetKeyboardIndicators(UIStateChangeType aShowAccelerators,
}
}
if (mHasFocus && mFocusedNode) { // send content state notifications
nsIDocument *doc = mFocusedNode->GetCurrentDoc();
if (doc) {
nsAutoScriptBlocker scriptBlocker;
doc->ContentStateChanged(mFocusedNode, NS_EVENT_STATE_FOCUSRING);
PRBool newShouldShowFocusRing = ShouldShowFocusRing();
if (mHasFocus && mFocusedNode &&
oldShouldShowFocusRing != newShouldShowFocusRing &&
mFocusedNode->IsElement()) {
// Update mFocusedNode's state.
if (newShouldShowFocusRing) {
mFocusedNode->AsElement()->AddStates(NS_EVENT_STATE_FOCUSRING);
} else {
mFocusedNode->AsElement()->RemoveStates(NS_EVENT_STATE_FOCUSRING);
}
}
}