Bug 591890 focus() method should be able to steal focus when it's called from mousedown event handler r=enndeakin, a=betaN+

This commit is contained in:
Masayuki Nakano 2010-11-06 14:04:11 +09:00
parent aad2bab723
commit d16a1c374e
7 changed files with 54 additions and 6 deletions

View File

@ -54,6 +54,8 @@
#include "nsCycleCollectionParticipant.h"
#include "nsIMarkupDocumentViewer.h"
#include "nsIScrollableFrame.h"
#include "nsFocusManager.h"
#include "nsIDocument.h"
class nsIPresShell;
class nsIDocShell;
@ -436,14 +438,25 @@ protected:
class nsAutoHandlingUserInputStatePusher
{
public:
nsAutoHandlingUserInputStatePusher(PRBool aIsHandlingUserInput, PRBool aIsMouseDown)
: mIsHandlingUserInput(aIsHandlingUserInput), mIsMouseDown(aIsMouseDown)
nsAutoHandlingUserInputStatePusher(PRBool aIsHandlingUserInput,
nsEvent* aEvent,
nsIDocument* aDocument)
: mIsHandlingUserInput(aIsHandlingUserInput),
mIsMouseDown(aEvent && aEvent->message == NS_MOUSE_BUTTON_DOWN),
mResetFMMouseDownState(PR_FALSE)
{
if (aIsHandlingUserInput) {
nsEventStateManager::StartHandlingUserInput();
if (aIsMouseDown) {
if (mIsMouseDown) {
nsIPresShell::SetCapturingContent(nsnull, 0);
nsIPresShell::AllowMouseCapture(PR_TRUE);
if (aDocument && NS_IS_TRUSTED_EVENT(aEvent)) {
nsFocusManager* fm = nsFocusManager::GetFocusManager();
if (fm) {
fm->SetMouseButtonDownHandlingDocument(aDocument);
mResetFMMouseDownState = PR_TRUE;
}
}
}
}
}
@ -454,6 +467,12 @@ public:
nsEventStateManager::StopHandlingUserInput();
if (mIsMouseDown) {
nsIPresShell::AllowMouseCapture(PR_FALSE);
if (mResetFMMouseDownState) {
nsFocusManager* fm = nsFocusManager::GetFocusManager();
if (fm) {
fm->SetMouseButtonDownHandlingDocument(nsnull);
}
}
}
}
}
@ -461,6 +480,7 @@ public:
protected:
PRBool mIsHandlingUserInput;
PRBool mIsMouseDown;
PRBool mResetFMMouseDownState;
private:
// Hide so that this class can only be stack-allocated

View File

@ -881,7 +881,9 @@ nsHTMLFormElement::SubmitSubmission(nsFormSubmission* aFormSubmission)
{
nsAutoPopupStatePusher popupStatePusher(mSubmitPopupState);
nsAutoHandlingUserInputStatePusher userInpStatePusher(mSubmitInitiatedFromUserInput, PR_FALSE);
nsAutoHandlingUserInputStatePusher userInpStatePusher(
mSubmitInitiatedFromUserInput,
nsnull, doc);
nsCOMPtr<nsIInputStream> postDataStream;
rv = aFormSubmission->GetEncodedSubmission(actionURI,

View File

@ -1126,6 +1126,12 @@ nsFocusManager::SetFocusInner(nsIContent* aNewContent, PRInt32 aFlags,
// is in chrome, any web contents should not be able to steal the focus.
nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(mFocusedContent));
sendFocusEvent = nsContentUtils::CanCallerAccess(domNode);
if (!sendFocusEvent && mMouseDownEventHandlingDocument) {
// However, while mouse down event is handling, the handling document's
// script should be able to steal focus.
domNode = do_QueryInterface(mMouseDownEventHandlingDocument);
sendFocusEvent = nsContentUtils::CanCallerAccess(domNode);
}
}
if (sendFocusEvent) {

View File

@ -88,6 +88,16 @@ public:
*/
nsresult ContentRemoved(nsIDocument* aDocument, nsIContent* aContent);
/**
* Called when mouse button down event handling is started and finished.
*/
void SetMouseButtonDownHandlingDocument(nsIDocument* aDocument)
{
NS_ASSERTION(!aDocument || !mMouseDownEventHandlingDocument,
"Some mouse button down events are nested?");
mMouseDownEventHandlingDocument = aDocument;
}
/**
* Returns the content node that would be focused if aWindow was in an
* active window. This will traverse down the frame hierarchy, starting at
@ -467,6 +477,14 @@ protected:
// and fire them later.
nsTArray<nsDelayedBlurOrFocusEvent> mDelayedBlurFocusEvents;
// A document which is handling a mouse button down event.
// When a mouse down event process is finished, ESM sets focus to the target
// content. Therefore, while DOM event handlers are handling mouse down
// events, the handlers should be able to steal focus from any elements even
// if focus is in chrome content. So, if this isn't NULL and the caller
// can access the document node, the caller should succeed in moving focus.
nsCOMPtr<nsIDocument> mMouseDownEventHandlingDocument;
// the single focus manager
static nsFocusManager* sInstance;
};

View File

@ -46,6 +46,7 @@ include $(topsrcdir)/config/rules.mk
_BROWSER_FILES = \
browser_focus_steal_from_chrome.js \
browser_focus_steal_from_chrome_during_mousedown.js \
browser_autofocus_background.js \
$(NULL)

View File

@ -6901,7 +6901,7 @@ PresShell::HandleEventInternal(nsEvent* aEvent, nsIView *aView,
}
nsAutoHandlingUserInputStatePusher userInpStatePusher(isHandlingUserInput,
aEvent->message == NS_MOUSE_BUTTON_DOWN);
aEvent, mDocument);
if (NS_IS_TRUSTED_EVENT(aEvent) && aEvent->message == NS_MOUSE_MOVE) {
nsIPresShell::AllowMouseCapture(

View File

@ -2264,7 +2264,8 @@ nsXULMenuCommandEvent::Run()
if (mCloseMenuMode != CloseMenuMode_None)
menuFrame->SelectMenu(PR_FALSE);
nsAutoHandlingUserInputStatePusher userInpStatePusher(mUserInput, PR_FALSE);
nsAutoHandlingUserInputStatePusher userInpStatePusher(mUserInput, nsnull,
shell->GetDocument());
nsContentUtils::DispatchXULCommand(mMenu, mIsTrusted, nsnull, shell,
mControl, mAlt, mShift, mMeta);
}