mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-03 23:30:46 +00:00
Bug 333198 - 'Suppress Input events for web content during synchronous XMLHttpRequest loads'. r=bz, sr=jst, a=blocking1.9.1+
This commit is contained in:
parent
08f13820ef
commit
fe25d33f34
@ -100,8 +100,8 @@ class nsFrameLoader;
|
||||
|
||||
// IID for the nsIDocument interface
|
||||
#define NS_IDOCUMENT_IID \
|
||||
{ 0x29f7a5d7, 0xb217, 0x4ea2, \
|
||||
{0x95, 0x40, 0x46, 0x41, 0xb9, 0xf5, 0x99, 0xd9 } }
|
||||
{ 0xdd9bd470, 0x6315, 0x4e67, \
|
||||
{ 0xa8, 0x8a, 0x78, 0xbf, 0x92, 0xb4, 0x5a, 0xdf } }
|
||||
|
||||
// Flag for AddStyleSheet().
|
||||
#define NS_STYLESHEET_FROM_CATALOG (1 << 0)
|
||||
@ -1117,6 +1117,20 @@ public:
|
||||
virtual nsSMILAnimationController* GetAnimationController() = 0;
|
||||
#endif // MOZ_SMIL
|
||||
|
||||
/**
|
||||
* Prevents user initiated events from being dispatched to the document and
|
||||
* subdocuments.
|
||||
*/
|
||||
virtual void SuppressEventHandling(PRUint32 aIncrease = 1) = 0;
|
||||
|
||||
virtual void UnsuppressEventHandlingAndFireEvents(PRBool aFireEvents) = 0;
|
||||
|
||||
void UnsuppressEventHandling()
|
||||
{
|
||||
UnsuppressEventHandlingAndFireEvents(PR_TRUE);
|
||||
}
|
||||
|
||||
PRUint32 EventHandlingSuppressed() { return mEventsSuppressed; }
|
||||
protected:
|
||||
~nsIDocument()
|
||||
{
|
||||
@ -1221,6 +1235,8 @@ protected:
|
||||
// go to.
|
||||
nsCOMPtr<nsIDocument> mDisplayDocument;
|
||||
|
||||
PRUint32 mEventsSuppressed;
|
||||
|
||||
private:
|
||||
// JSObject cache. Only to be used for performance
|
||||
// optimizations. This will be set once this document is touched
|
||||
|
@ -6888,6 +6888,10 @@ CanCacheSubDocument(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
||||
PRBool
|
||||
nsDocument::CanSavePresentation(nsIRequest *aNewRequest)
|
||||
{
|
||||
if (EventHandlingSuppressed()) {
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
// Check our event listener manager for unload/beforeunload listeners.
|
||||
nsCOMPtr<nsPIDOMEventTarget> piTarget = do_QueryInterface(mScriptGlobalObject);
|
||||
if (piTarget) {
|
||||
@ -7496,3 +7500,51 @@ nsDocument::GetReadyState(nsAString& aReadyState)
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static PRBool
|
||||
SuppressEventHandlingInDocument(nsIDocument* aDocument, void* aData)
|
||||
{
|
||||
aDocument->SuppressEventHandling(*static_cast<PRUint32*>(aData));
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::SuppressEventHandling(PRUint32 aIncrease)
|
||||
{
|
||||
mEventsSuppressed += aIncrease;
|
||||
EnumerateSubDocuments(SuppressEventHandlingInDocument, &aIncrease);
|
||||
}
|
||||
|
||||
static PRBool
|
||||
GetAndUnsuppressSubDocuments(nsIDocument* aDocument, void* aData)
|
||||
{
|
||||
PRUint32 suppression = aDocument->EventHandlingSuppressed();
|
||||
if (suppression > 0) {
|
||||
static_cast<nsDocument*>(aDocument)->DecreaseEventSuppression();
|
||||
}
|
||||
nsCOMArray<nsIDocument>* docs = static_cast<nsCOMArray<nsIDocument>* >(aData);
|
||||
docs->AppendObject(aDocument);
|
||||
aDocument->EnumerateSubDocuments(GetAndUnsuppressSubDocuments, docs);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::UnsuppressEventHandlingAndFireEvents(PRBool aFireEvents)
|
||||
{
|
||||
if (mEventsSuppressed > 0) {
|
||||
--mEventsSuppressed;
|
||||
}
|
||||
nsCOMArray<nsIDocument> documents;
|
||||
documents.AppendObject(this);
|
||||
EnumerateSubDocuments(GetAndUnsuppressSubDocuments, &documents);
|
||||
for (PRInt32 i = 0; i < documents.Count(); ++i) {
|
||||
if (!documents[i]->EventHandlingSuppressed()) {
|
||||
nsPresShellIterator iter(documents[i]);
|
||||
nsCOMPtr<nsIPresShell> shell;
|
||||
while ((shell = iter.GetNextShell())) {
|
||||
shell->FireOrClearDelayedEvents(aFireEvents);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -986,6 +986,12 @@ public:
|
||||
nsSMILAnimationController* GetAnimationController();
|
||||
#endif // MOZ_SMIL
|
||||
|
||||
virtual void SuppressEventHandling(PRUint32 aIncrease);
|
||||
|
||||
virtual void UnsuppressEventHandlingAndFireEvents(PRBool aFireEvents);
|
||||
|
||||
void DecreaseEventSuppression() { --mEventsSuppressed; }
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDocument, nsIDocument)
|
||||
|
||||
/**
|
||||
|
@ -2160,7 +2160,8 @@ nsXMLHttpRequest::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
||||
request->GetStatus(&status);
|
||||
mErrorLoad = mErrorLoad || NS_FAILED(status);
|
||||
|
||||
if (mUpload && !mUploadComplete && !mErrorLoad) {
|
||||
if (mUpload && !mUploadComplete && !mErrorLoad &&
|
||||
(mState & XML_HTTP_REQUEST_ASYNC)) {
|
||||
mUploadComplete = PR_TRUE;
|
||||
DispatchProgressEvent(mUpload, NS_LITERAL_STRING(LOAD_STR),
|
||||
PR_TRUE, mUploadTotal, mUploadTotal);
|
||||
@ -2786,12 +2787,17 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
|
||||
if (!(mState & XML_HTTP_REQUEST_ASYNC)) {
|
||||
mState |= XML_HTTP_REQUEST_SYNCLOOPING;
|
||||
|
||||
nsCOMPtr<nsIDocument> suspendedDoc;
|
||||
nsCOMPtr<nsIRunnable> resumeTimeoutRunnable;
|
||||
if (mOwner) {
|
||||
nsCOMPtr<nsIDOMWindow> topWindow;
|
||||
if (NS_SUCCEEDED(mOwner->GetTop(getter_AddRefs(topWindow)))) {
|
||||
nsCOMPtr<nsPIDOMWindow> suspendedWindow(do_QueryInterface(topWindow));
|
||||
if (suspendedWindow) {
|
||||
suspendedDoc = do_QueryInterface(suspendedWindow->GetExtantDocument());
|
||||
if (suspendedDoc) {
|
||||
suspendedDoc->SuppressEventHandling();
|
||||
}
|
||||
suspendedWindow->SuspendTimeouts();
|
||||
resumeTimeoutRunnable = NS_NEW_RUNNABLE_METHOD(nsPIDOMWindow,
|
||||
suspendedWindow.get(),
|
||||
@ -2808,6 +2814,12 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
|
||||
}
|
||||
}
|
||||
|
||||
if (suspendedDoc) {
|
||||
NS_DispatchToCurrentThread(
|
||||
NS_NEW_RUNNABLE_METHOD(nsIDocument, suspendedDoc.get(),
|
||||
UnsuppressEventHandling));
|
||||
}
|
||||
|
||||
if (resumeTimeoutRunnable) {
|
||||
NS_DispatchToCurrentThread(resumeTimeoutRunnable);
|
||||
}
|
||||
@ -3222,7 +3234,7 @@ nsXMLHttpRequest::OnProgress(nsIRequest *aRequest, nsISupports *aContext, PRUint
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!mErrorLoad) {
|
||||
if (!mErrorLoad && (mState & XML_HTTP_REQUEST_ASYNC)) {
|
||||
StartProgressEventTimer();
|
||||
NS_NAMED_LITERAL_STRING(progress, PROGRESS_STR);
|
||||
NS_NAMED_LITERAL_STRING(uploadprogress, UPLOADPROGRESS_STR);
|
||||
@ -3348,7 +3360,8 @@ NS_IMETHODIMP
|
||||
nsXMLHttpRequest::Notify(nsITimer* aTimer)
|
||||
{
|
||||
mTimerIsActive = PR_FALSE;
|
||||
if (NS_SUCCEEDED(CheckInnerWindowCorrectness()) && !mErrorLoad) {
|
||||
if (NS_SUCCEEDED(CheckInnerWindowCorrectness()) && !mErrorLoad &&
|
||||
(mState & XML_HTTP_REQUEST_ASYNC)) {
|
||||
if (mProgressEventWasDelayed) {
|
||||
mProgressEventWasDelayed = PR_FALSE;
|
||||
if (!(XML_HTTP_REQUEST_MPART_HEADERS & mState)) {
|
||||
|
@ -146,6 +146,7 @@ _TEST_FILES = test_bug5141.html \
|
||||
file_bug326337.xml \
|
||||
file_bug326337_multipart.txt \
|
||||
file_bug326337_multipart.txt^headers^ \
|
||||
test_bug333198.html \
|
||||
test_bug402150.html \
|
||||
test_bug402150.html^headers^ \
|
||||
test_bug401662.html \
|
||||
|
73
content/base/test/test_bug333198.html
Normal file
73
content/base/test/test_bug333198.html
Normal file
@ -0,0 +1,73 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=333198
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 333198</title>
|
||||
<script type="application/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<iframe id="ifr"></iframe><br>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=333198">Mozilla Bug 333198</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 333198 **/
|
||||
|
||||
var eventCount = 0;
|
||||
function clickHandler() {
|
||||
++eventCount;
|
||||
}
|
||||
|
||||
function suppressEvents(suppress) {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsIDOMWindowUtils)
|
||||
.suppressEventHandling(suppress);
|
||||
}
|
||||
|
||||
function sendEvents() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
windowUtils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
windowUtils.sendMouseEvent("mousedown", 1, 1, 0, 1, 0);
|
||||
windowUtils.sendMouseEvent("mouseup", 1, 1, 0, 1, 0);
|
||||
|
||||
iframeUtils = document.getElementById("ifr").contentWindow
|
||||
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||
.getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||
iframeUtils.sendMouseEvent("mousedown", 1, 1, 0, 1, 0);
|
||||
iframeUtils.sendMouseEvent("mouseup", 1, 1, 0, 1, 0);
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
window.addEventListener("click", clickHandler, true);
|
||||
var ifr = document.getElementById("ifr")
|
||||
ifr.contentWindow.addEventListener("click", clickHandler, true);
|
||||
sendEvents();
|
||||
is(eventCount, 2, "Wrong event count(1)");
|
||||
suppressEvents(true);
|
||||
sendEvents();
|
||||
is(eventCount, 2, "Wrong event count(2)");
|
||||
suppressEvents(false);
|
||||
sendEvents();
|
||||
is(eventCount, 4, "Wrong event count(2)");
|
||||
if (eventCount != 4)
|
||||
alert(eventCount);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(runTest);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -260,6 +260,40 @@ PrintDocTreeAll(nsIDocShellTreeItem* aItem)
|
||||
}
|
||||
#endif
|
||||
|
||||
static nsIDocument*
|
||||
EventHandlingSuppressed(nsPIDOMEventTarget* aTarget)
|
||||
{
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(aTarget);
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
if (node) {
|
||||
doc = node->GetOwnerDoc();
|
||||
} else {
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aTarget);
|
||||
if (window) {
|
||||
doc = do_QueryInterface(window->GetExtantDocument());
|
||||
}
|
||||
}
|
||||
|
||||
return (doc && doc->EventHandlingSuppressed()) ? doc : nsnull;
|
||||
}
|
||||
|
||||
static void
|
||||
FireBlurEvent(nsPIDOMEventTarget* aTarget, nsEvent* aEvent, nsPresContext* aContext)
|
||||
{
|
||||
NS_ASSERTION(aEvent->message == NS_BLUR_CONTENT, "Wrong event!");
|
||||
nsIDocument* doc = EventHandlingSuppressed(aTarget);
|
||||
if (doc) {
|
||||
if (aContext) {
|
||||
nsIPresShell* shell = aContext->GetPresShell();
|
||||
if (shell) {
|
||||
shell->NeedsBlurAfterSuppression(aTarget);
|
||||
}
|
||||
}
|
||||
} else if (aTarget) {
|
||||
nsEventDispatcher::Dispatch(aTarget, aContext, aEvent);
|
||||
}
|
||||
}
|
||||
|
||||
class nsUITimerCallback : public nsITimerCallback
|
||||
{
|
||||
public:
|
||||
@ -1092,14 +1126,11 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
if (!isAlreadySuppressed) {
|
||||
|
||||
// Fire the blur event on the previously focused document.
|
||||
nsEvent blurEvent(PR_TRUE, NS_BLUR_CONTENT);
|
||||
blurEvent.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
|
||||
|
||||
nsEventStatus blurstatus = nsEventStatus_eIgnore;
|
||||
nsEvent blurevent(PR_TRUE, NS_BLUR_CONTENT);
|
||||
blurevent.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
|
||||
|
||||
nsEventDispatcher::Dispatch(gLastFocusedDocument,
|
||||
gLastFocusedPresContextWeak,
|
||||
&blurevent, nsnull, &blurstatus);
|
||||
FireBlurEvent(gLastFocusedDocument, &blurEvent,
|
||||
gLastFocusedPresContextWeak);
|
||||
|
||||
nsCOMPtr<nsIEventStateManager> esm;
|
||||
if (!mCurrentFocus && gLastFocusedContent) {
|
||||
@ -1120,16 +1151,15 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
}
|
||||
}
|
||||
nsCOMPtr<nsIContent> blurContent = gLastFocusedContent;
|
||||
blurevent.target = nsnull;
|
||||
nsEventDispatcher::Dispatch(gLastFocusedContent,
|
||||
gLastFocusedPresContextWeak,
|
||||
&blurevent, nsnull, &blurstatus);
|
||||
blurEvent.target = nsnull;
|
||||
FireBlurEvent(gLastFocusedContent, &blurEvent,
|
||||
gLastFocusedPresContextWeak);
|
||||
}
|
||||
if (ourWindow) {
|
||||
// Clear the target so that Dispatch can set it back correctly.
|
||||
blurevent.target = nsnull;
|
||||
nsEventDispatcher::Dispatch(ourWindow, gLastFocusedPresContextWeak,
|
||||
&blurevent, nsnull, &blurstatus);
|
||||
blurEvent.target = nsnull;
|
||||
nsCOMPtr<nsPIDOMEventTarget> win = do_QueryInterface(ourWindow);
|
||||
FireBlurEvent(win, &blurEvent, gLastFocusedPresContextWeak);
|
||||
}
|
||||
|
||||
if (esm) {
|
||||
@ -1259,10 +1289,8 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
|
||||
// Now fire blurs. We fire a blur on the focused document, element,
|
||||
// and window.
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
nsEvent event(PR_TRUE, NS_BLUR_CONTENT);
|
||||
event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
|
||||
nsEvent blurEvent(PR_TRUE, NS_BLUR_CONTENT);
|
||||
blurEvent.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
|
||||
|
||||
if (gLastFocusedDocument && gLastFocusedPresContextWeak) {
|
||||
if (gLastFocusedContent) {
|
||||
@ -1278,8 +1306,7 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
nsCOMPtr<nsIEventStateManager> esm =
|
||||
oldPresContext->EventStateManager();
|
||||
esm->SetFocusedContent(gLastFocusedContent);
|
||||
nsEventDispatcher::Dispatch(gLastFocusedContent, oldPresContext,
|
||||
&event, nsnull, &status);
|
||||
FireBlurEvent(gLastFocusedContent, &blurEvent, oldPresContext);
|
||||
esm->SetFocusedContent(nsnull);
|
||||
NS_IF_RELEASE(gLastFocusedContent);
|
||||
}
|
||||
@ -1301,15 +1328,13 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window(lastFocusedDocument->GetWindow());
|
||||
|
||||
event.target = nsnull;
|
||||
nsEventDispatcher::Dispatch(lastFocusedDocument,
|
||||
lastFocusedPresContext,
|
||||
&event, nsnull, &status);
|
||||
blurEvent.target = nsnull;
|
||||
FireBlurEvent(lastFocusedDocument, &blurEvent, lastFocusedPresContext);
|
||||
|
||||
if (window) {
|
||||
event.target = nsnull;
|
||||
nsEventDispatcher::Dispatch(window, lastFocusedPresContext,
|
||||
&event, nsnull, &status);
|
||||
blurEvent.target = nsnull;
|
||||
nsCOMPtr<nsPIDOMEventTarget> win = do_QueryInterface(window);
|
||||
FireBlurEvent(win, &blurEvent ,lastFocusedPresContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1442,10 +1467,9 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
mFirstDocumentBlurEvent = gLastFocusedDocument;
|
||||
clearFirstDocumentBlurEvent = PR_TRUE;
|
||||
}
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
nsEvent event(PR_TRUE, NS_BLUR_CONTENT);
|
||||
event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
|
||||
|
||||
nsEvent blurEvent(PR_TRUE, NS_BLUR_CONTENT);
|
||||
blurEvent.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
|
||||
|
||||
if (gLastFocusedContent) {
|
||||
nsIPresShell *shell = gLastFocusedDocument->GetPrimaryShell();
|
||||
@ -1463,8 +1487,7 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
nsCOMPtr<nsIContent> focusedContent = do_QueryInterface(focusedElement);
|
||||
if (focusedContent) {
|
||||
// Blur the element.
|
||||
nsEventDispatcher::Dispatch(focusedContent, oldPresContext,
|
||||
&event, nsnull, &status);
|
||||
FireBlurEvent(focusedContent, &blurEvent, oldPresContext);
|
||||
}
|
||||
|
||||
esm->SetFocusedContent(nsnull);
|
||||
@ -1479,14 +1502,13 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
gLastFocusedPresContextWeak = nsnull;
|
||||
|
||||
// fire blur on document and window
|
||||
event.target = nsnull;
|
||||
nsEventDispatcher::Dispatch(mDocument, aPresContext, &event, nsnull,
|
||||
&status);
|
||||
blurEvent.target = nsnull;
|
||||
FireBlurEvent(mDocument, &blurEvent, aPresContext);
|
||||
|
||||
if (ourWindow) {
|
||||
event.target = nsnull;
|
||||
nsEventDispatcher::Dispatch(ourWindow, aPresContext, &event, nsnull,
|
||||
&status);
|
||||
blurEvent.target = nsnull;
|
||||
nsCOMPtr<nsPIDOMEventTarget> win = do_QueryInterface(ourWindow);
|
||||
FireBlurEvent(win, &blurEvent, aPresContext);
|
||||
}
|
||||
if (clearFirstDocumentBlurEvent) {
|
||||
mFirstDocumentBlurEvent = nsnull;
|
||||
@ -4322,7 +4344,7 @@ nsEventStateManager::ShiftFocusInternal(PRBool aForward, nsIContent* aStart)
|
||||
if (doc) {
|
||||
nsIDocument *sub_doc = doc->GetSubDocumentFor(nextFocus);
|
||||
|
||||
if (sub_doc) {
|
||||
if (sub_doc && !sub_doc->EventHandlingSuppressed()) {
|
||||
nsCOMPtr<nsISupports> container = sub_doc->GetContainer();
|
||||
sub_shell = do_QueryInterface(container);
|
||||
}
|
||||
@ -5184,9 +5206,8 @@ nsEventStateManager::SendFocusBlur(nsPresContext* aPresContext,
|
||||
nsCOMPtr<nsPresContext> oldPresContext = shell->GetPresContext();
|
||||
|
||||
//fire blur
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
nsEvent event(PR_TRUE, NS_BLUR_CONTENT);
|
||||
event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
|
||||
nsEvent blurEvent(PR_TRUE, NS_BLUR_CONTENT);
|
||||
blurEvent.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
|
||||
|
||||
EnsureDocument(presShell);
|
||||
|
||||
@ -5217,8 +5238,7 @@ nsEventStateManager::SendFocusBlur(nsPresContext* aPresContext,
|
||||
|
||||
nsCxPusher pusher;
|
||||
if (pusher.Push(temp)) {
|
||||
nsEventDispatcher::Dispatch(temp, oldPresContext, &event, nsnull,
|
||||
&status);
|
||||
FireBlurEvent(temp, &blurEvent, oldPresContext);
|
||||
pusher.Pop();
|
||||
}
|
||||
|
||||
@ -5250,9 +5270,8 @@ nsEventStateManager::SendFocusBlur(nsPresContext* aPresContext,
|
||||
|
||||
if (gLastFocusedDocument && (gLastFocusedDocument != mDocument) &&
|
||||
window) {
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
nsEvent event(PR_TRUE, NS_BLUR_CONTENT);
|
||||
event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
|
||||
nsEvent blurEvent(PR_TRUE, NS_BLUR_CONTENT);
|
||||
blurEvent.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
|
||||
|
||||
// Make sure we're not switching command dispatchers, if so,
|
||||
// suppress the blurred one if it isn't already suppressed
|
||||
@ -5280,8 +5299,7 @@ nsEventStateManager::SendFocusBlur(nsPresContext* aPresContext,
|
||||
|
||||
nsCxPusher pusher;
|
||||
if (pusher.Push(temp)) {
|
||||
nsEventDispatcher::Dispatch(temp, gLastFocusedPresContextWeak, &event,
|
||||
nsnull, &status);
|
||||
FireBlurEvent(temp, &blurEvent, gLastFocusedPresContextWeak);
|
||||
pusher.Pop();
|
||||
}
|
||||
|
||||
@ -5296,9 +5314,9 @@ nsEventStateManager::SendFocusBlur(nsPresContext* aPresContext,
|
||||
|
||||
nsCOMPtr<nsPIDOMEventTarget> target = do_QueryInterface(window);
|
||||
if (pusher.Push(target)) {
|
||||
nsEventDispatcher::Dispatch(window, gLastFocusedPresContextWeak, &event,
|
||||
nsnull, &status);
|
||||
|
||||
blurEvent.target = nsnull;
|
||||
FireBlurEvent(target, &blurEvent, gLastFocusedPresContextWeak);
|
||||
|
||||
if (previousFocus && mCurrentFocus != previousFocus) {
|
||||
// The window's blur handler focused something else.
|
||||
// Abort firing any additional blur or focus events.
|
||||
@ -5351,7 +5369,8 @@ nsEventStateManager::SendFocusBlur(nsPresContext* aPresContext,
|
||||
widget->SetFocus(PR_TRUE);
|
||||
}
|
||||
|
||||
if (nsnull != aContent && aContent != mFirstFocusEvent) {
|
||||
if (nsnull != aContent && aContent != mFirstFocusEvent &&
|
||||
!EventHandlingSuppressed(aContent)) {
|
||||
|
||||
//Store the first focus event we fire and don't refire focus
|
||||
//to that element while the first focus is still ongoing.
|
||||
@ -5386,7 +5405,7 @@ nsEventStateManager::SendFocusBlur(nsPresContext* aPresContext,
|
||||
}
|
||||
|
||||
nsIMEStateManager::OnTextStateFocus(mPresContext, mCurrentFocus);
|
||||
} else if (!aContent) {
|
||||
} else if (!aContent && !EventHandlingSuppressed(mDocument)) {
|
||||
//fire focus on document even if the content isn't focusable (ie. text)
|
||||
//see bugzilla bug 93521
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
|
@ -6021,6 +6021,14 @@ nsDocShell::RestoreFromHistory()
|
||||
|
||||
nsCOMPtr<nsIDocument> document = do_QueryInterface(domDoc);
|
||||
if (document) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> parent;
|
||||
GetParent(getter_AddRefs(parent));
|
||||
nsCOMPtr<nsIDOMDocument> parentDoc = do_GetInterface(parent);
|
||||
nsCOMPtr<nsIDocument> d = do_QueryInterface(parentDoc);
|
||||
if (d && d->EventHandlingSuppressed()) {
|
||||
document->SuppressEventHandling(d->EventHandlingSuppressed());
|
||||
}
|
||||
|
||||
// Use the uri from the mLSHE we had when we entered this function
|
||||
// (which need not match the document's URI if anchors are involved),
|
||||
// since that's the history entry we're loading. Note that if we use
|
||||
|
@ -48,7 +48,7 @@
|
||||
interface nsIDOMElement;
|
||||
interface nsIDOMHTMLCanvasElement;
|
||||
|
||||
[scriptable, uuid(8C6263C9-F3EF-419d-80EF-D5D716635FAA)]
|
||||
[scriptable, uuid(6e3510b9-806d-4a2a-be79-73d2a495b4b8)]
|
||||
interface nsIDOMWindowUtils : nsISupports {
|
||||
|
||||
/**
|
||||
@ -298,6 +298,15 @@ interface nsIDOMWindowUtils : nsISupports {
|
||||
*/
|
||||
readonly attribute boolean isMozAfterPaintPending;
|
||||
|
||||
/**
|
||||
* Suppresses/unsuppresses user initiated event handling in window's document
|
||||
* and subdocuments.
|
||||
*
|
||||
* @throw NS_ERROR_DOM_SECURITY_ERR if called without UniversalXPConnect
|
||||
* privileges and NS_ERROR_FAILURE if window doesn't have a document.
|
||||
*/
|
||||
void suppressEventHandling(in boolean aSuppress);
|
||||
|
||||
/**
|
||||
* Disable or enable non synthetic test mouse events on *all* windows.
|
||||
*
|
||||
|
@ -700,3 +700,22 @@ nsDOMWindowUtils::DisableNonTestMouseEvents(PRBool aDisable)
|
||||
NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
|
||||
return presShell->DisableNonTestMouseEvents(aDisable);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::SuppressEventHandling(PRBool aSuppress)
|
||||
{
|
||||
PRBool hasCap = PR_FALSE;
|
||||
if (NS_FAILED(nsContentUtils::GetSecurityManager()->IsCapabilityEnabled("UniversalXPConnect", &hasCap)) || !hasCap)
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
|
||||
nsCOMPtr<nsIDocument> doc(do_QueryInterface(mWindow->GetExtantDocument()));
|
||||
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
|
||||
|
||||
if (aSuppress) {
|
||||
doc->SuppressEventHandling();
|
||||
} else {
|
||||
doc->UnsuppressEventHandling();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -5611,9 +5611,17 @@ nsGlobalWindow::EnterModalState()
|
||||
return;
|
||||
}
|
||||
|
||||
static_cast<nsGlobalWindow *>
|
||||
(static_cast<nsIDOMWindow *>
|
||||
(top.get()))->mModalStateDepth++;
|
||||
nsGlobalWindow* topWin =
|
||||
static_cast<nsGlobalWindow*>(static_cast<nsIDOMWindow *>(top.get()));
|
||||
if (topWin->mModalStateDepth == 0) {
|
||||
NS_ASSERTION(!mSuspendedDoc, "Shouldn't have mSuspendedDoc here!");
|
||||
|
||||
mSuspendedDoc = do_QueryInterface(topWin->GetExtantDocument());
|
||||
if (mSuspendedDoc) {
|
||||
mSuspendedDoc->SuppressEventHandling();
|
||||
}
|
||||
}
|
||||
topWin->mModalStateDepth++;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -5709,6 +5717,22 @@ nsGlobalWindow::LeaveModalState()
|
||||
nsCOMPtr<nsIRunnable> runner = new nsPendingTimeoutRunner(topWin);
|
||||
if (NS_FAILED(NS_DispatchToCurrentThread(runner)))
|
||||
NS_WARNING("failed to dispatch pending timeout runnable");
|
||||
|
||||
if (mSuspendedDoc) {
|
||||
nsCOMPtr<nsIDocument> currentDoc =
|
||||
do_QueryInterface(topWin->GetExtantDocument());
|
||||
if (currentDoc == mSuspendedDoc) {
|
||||
NS_DispatchToCurrentThread(
|
||||
NS_NEW_RUNNABLE_METHOD(nsIDocument, mSuspendedDoc.get(),
|
||||
UnsuppressEventHandling));
|
||||
} else {
|
||||
// Somehow the document was changed.
|
||||
// Unsuppress event handling in the document but don't even
|
||||
// try to fire events.
|
||||
mSuspendedDoc->UnsuppressEventHandlingAndFireEvents(PR_FALSE);
|
||||
}
|
||||
mSuspendedDoc = nsnull;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -744,6 +744,8 @@ protected:
|
||||
|
||||
nsDataHashtable<nsVoidPtrHashKey, void*> mCachedXBLPrototypeHandlers;
|
||||
|
||||
nsCOMPtr<nsIDocument> mSuspendedDoc;
|
||||
|
||||
friend class nsDOMScriptableHelper;
|
||||
friend class nsDOMWindowUtils;
|
||||
friend class PostMessageEvent;
|
||||
|
@ -629,6 +629,9 @@ DocumentViewerImpl::SyncParentSubDocMap()
|
||||
nsCOMPtr<nsIDocument> parent_doc(do_QueryInterface(dom_doc));
|
||||
|
||||
if (parent_doc) {
|
||||
if (mDocument && parent_doc->GetSubDocumentFor(content) != mDocument) {
|
||||
mDocument->SuppressEventHandling(parent_doc->EventHandlingSuppressed());
|
||||
}
|
||||
return parent_doc->SetSubDocumentFor(content, mDocument);
|
||||
}
|
||||
}
|
||||
|
@ -97,14 +97,15 @@ class nsWeakFrame;
|
||||
class nsIScrollableFrame;
|
||||
class gfxASurface;
|
||||
class gfxContext;
|
||||
class nsPIDOMEventTarget;
|
||||
|
||||
typedef short SelectionType;
|
||||
typedef PRUint32 nsFrameState;
|
||||
|
||||
// 445e6184-5e7e-4a9b-97f7-c9391e6773d2
|
||||
#define NS_IPRESSHELL_IID \
|
||||
{ 0x445e6184, 0x5e7e, 0x4a9b, \
|
||||
{ 0x97, 0xf7, 0xc9, 0x39, 0x1e, 0x67, 0x73, 0xd2 } }
|
||||
// 8355e7a9-4118-47dc-97e3-a3c251332e86
|
||||
#define NS_IPRESSHELL_IID \
|
||||
{ 0x8355e7a9, 0x4118, 0x47dc, \
|
||||
{ 0x97, 0xe3, 0xa3, 0xc2, 0x51, 0x33, 0x2e, 0x86 } }
|
||||
|
||||
// Constants for ScrollContentIntoView() function
|
||||
#define NS_PRESSHELL_SCROLL_TOP 0
|
||||
@ -692,6 +693,9 @@ public:
|
||||
*/
|
||||
virtual void Thaw() = 0;
|
||||
|
||||
virtual void NeedsBlurAfterSuppression(nsPIDOMEventTarget* aTarget) = 0;
|
||||
virtual void FireOrClearDelayedEvents(PRBool aFireEvents) = 0;
|
||||
|
||||
/**
|
||||
* When this shell is disconnected from its containing docshell, we
|
||||
* lose our container pointer. However, we'd still like to be able to target
|
||||
|
@ -880,6 +880,8 @@ public:
|
||||
virtual nsresult ReconstructFrames(void);
|
||||
virtual void Freeze();
|
||||
virtual void Thaw();
|
||||
virtual void NeedsBlurAfterSuppression(nsPIDOMEventTarget* aTarget);
|
||||
virtual void FireOrClearDelayedEvents(PRBool aFireEvents);
|
||||
|
||||
virtual nsIFrame* GetFrameForPoint(nsIFrame* aFrame, nsPoint aPt);
|
||||
|
||||
@ -1152,6 +1154,13 @@ protected:
|
||||
|
||||
nsRevocableEventPtr<ReflowEvent> mReflowEvent;
|
||||
|
||||
PRPackedBool mNeedsGotFocus;
|
||||
PRPackedBool mNeedsLostFocus;
|
||||
PRPackedBool mMozTakingFocus;
|
||||
PRPackedBool mNeedsActivate;
|
||||
PRPackedBool mNeedsDeactivate;
|
||||
nsCOMArray<nsPIDOMEventTarget> mDelayedBlurTargets;
|
||||
|
||||
nsCallbackEventRequest* mFirstCallbackEventRequest;
|
||||
nsCallbackEventRequest* mLastCallbackEventRequest;
|
||||
|
||||
@ -5621,6 +5630,37 @@ PresShell::HandleEvent(nsIView *aView,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mDocument && mDocument->EventHandlingSuppressed()) {
|
||||
switch (aEvent->message) {
|
||||
case NS_GOTFOCUS:
|
||||
mNeedsGotFocus = PR_TRUE;
|
||||
mNeedsLostFocus = PR_FALSE;
|
||||
mNeedsDeactivate = PR_FALSE;
|
||||
break;
|
||||
case NS_LOSTFOCUS:
|
||||
mNeedsLostFocus = PR_TRUE;
|
||||
mNeedsGotFocus = PR_FALSE;
|
||||
mNeedsActivate = PR_FALSE;
|
||||
mMozTakingFocus =
|
||||
(aEvent->eventStructType == NS_FOCUS_EVENT &&
|
||||
static_cast<nsFocusEvent*>(aEvent)->isMozWindowTakingFocus);
|
||||
break;
|
||||
case NS_ACTIVATE:
|
||||
mNeedsActivate = PR_TRUE;
|
||||
mNeedsDeactivate = PR_FALSE;
|
||||
mNeedsLostFocus = PR_FALSE;
|
||||
break;
|
||||
case NS_DEACTIVATE:
|
||||
mNeedsDeactivate = PR_TRUE;
|
||||
mNeedsActivate = PR_FALSE;
|
||||
mNeedsGotFocus = PR_FALSE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIFrame* frame = static_cast<nsIFrame*>(aView->GetClientData());
|
||||
|
||||
PRBool dispatchUsingCoordinates =
|
||||
@ -6477,6 +6517,79 @@ PresShell::Freeze()
|
||||
mDocument->EnumerateSubDocuments(FreezeSubDocument, nsnull);
|
||||
}
|
||||
|
||||
void
|
||||
PresShell::FireOrClearDelayedEvents(PRBool aFireEvents)
|
||||
{
|
||||
if (!aFireEvents) {
|
||||
mDelayedBlurTargets.Clear();
|
||||
mNeedsGotFocus = mNeedsLostFocus = mMozTakingFocus = mNeedsActivate =
|
||||
mNeedsDeactivate = PR_FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mIsDestroying && mDocument) {
|
||||
nsCOMPtr<nsIDocument> doc = mDocument;
|
||||
for (PRInt32 i = 0;
|
||||
(i < mDelayedBlurTargets.Count()) &&
|
||||
!doc->EventHandlingSuppressed(); ++i) {
|
||||
nsEvent blurevent(PR_TRUE, NS_BLUR_CONTENT);
|
||||
blurevent.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
|
||||
nsEventDispatcher::Dispatch(mDelayedBlurTargets[i], mPresContext, &blurevent);
|
||||
}
|
||||
mDelayedBlurTargets.Clear();
|
||||
|
||||
nsFocusEvent firstEvent(PR_TRUE, NS_EVENT_NULL, nsnull);
|
||||
nsFocusEvent secondEvent(PR_TRUE, NS_EVENT_NULL, nsnull);
|
||||
if (mNeedsGotFocus) {
|
||||
firstEvent.message = NS_GOTFOCUS;
|
||||
} else if (mNeedsDeactivate) {
|
||||
firstEvent.message = NS_DEACTIVATE;
|
||||
}
|
||||
if (mNeedsActivate) {
|
||||
secondEvent.message = NS_ACTIVATE;
|
||||
} else if (mNeedsLostFocus) {
|
||||
secondEvent.message = NS_LOSTFOCUS;
|
||||
secondEvent.isMozWindowTakingFocus = mMozTakingFocus;
|
||||
}
|
||||
mNeedsGotFocus = mNeedsLostFocus = mMozTakingFocus = mNeedsActivate =
|
||||
mNeedsDeactivate = PR_FALSE;
|
||||
|
||||
if (firstEvent.message && !mIsDestroying &&
|
||||
!doc->EventHandlingSuppressed()) {
|
||||
nsIViewManager* vm = GetViewManager();
|
||||
if (vm) {
|
||||
nsIView* view = nsnull;
|
||||
vm->GetRootView(view);
|
||||
if (view) {
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
HandleEvent(view, &firstEvent, &status);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (secondEvent.message && !mIsDestroying &&
|
||||
!doc->EventHandlingSuppressed()) {
|
||||
nsIViewManager* vm = GetViewManager();
|
||||
if (vm) {
|
||||
nsIView* view = nsnull;
|
||||
vm->GetRootView(view);
|
||||
if (view) {
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
HandleEvent(view, &secondEvent, &status);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PresShell::NeedsBlurAfterSuppression(nsPIDOMEventTarget* aTarget)
|
||||
{
|
||||
if (mDocument && mDocument->EventHandlingSuppressed()) {
|
||||
mDelayedBlurTargets.RemoveObject(aTarget);
|
||||
mDelayedBlurTargets.AppendObject(aTarget);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
StartPluginInstance(PresShell *aShell, nsIContent *aContent)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user