Bug 333198 - Suppress Input events for web content during synchronous XMLHttpRequest loads, r=bz, sr=jst

This commit is contained in:
Olli Pettay 2009-03-03 22:11:14 +02:00
Родитель 9b3d4a26c8
Коммит 739ee979a1
15 изменённых файлов: 454 добавлений и 73 удалений

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

@ -101,8 +101,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)
@ -1128,6 +1128,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()
{
@ -1232,6 +1246,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,15 @@ CanCacheSubDocument(PLDHashTable *table, PLDHashEntryHdr *hdr,
PRBool
nsDocument::CanSavePresentation(nsIRequest *aNewRequest)
{
if (EventHandlingSuppressed()) {
return PR_FALSE;
}
nsPIDOMWindow* win = GetInnerWindow();
if (win && win->TimeoutSuspendCount()) {
return PR_FALSE;
}
// Check our event listener manager for unload/beforeunload listeners.
nsCOMPtr<nsPIDOMEventTarget> piTarget = do_QueryInterface(mScriptGlobalObject);
if (piTarget) {
@ -7512,3 +7521,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)
/**

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

@ -145,6 +145,21 @@
#define NS_PROGRESS_EVENT_INTERVAL 50
class nsResumeTimeoutsEvent : public nsRunnable
{
public:
nsResumeTimeoutsEvent(nsPIDOMWindow* aWindow) : mWindow(aWindow) {}
NS_IMETHOD Run()
{
mWindow->ResumeTimeouts(PR_FALSE);
return NS_OK;
}
private:
nsCOMPtr<nsPIDOMWindow> mWindow;
};
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMEventListenerWrapper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMEventListenerWrapper)
@ -2160,7 +2175,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,16 +2802,20 @@ 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) {
suspendedWindow->SuspendTimeouts();
resumeTimeoutRunnable = NS_NEW_RUNNABLE_METHOD(nsPIDOMWindow,
suspendedWindow.get(),
ResumeTimeouts);
if (suspendedWindow &&
(suspendedWindow = suspendedWindow->GetCurrentInnerWindow())) {
suspendedDoc = do_QueryInterface(suspendedWindow->GetExtantDocument());
if (suspendedDoc) {
suspendedDoc->SuppressEventHandling();
}
suspendedWindow->SuspendTimeouts(1, PR_FALSE);
resumeTimeoutRunnable = new nsResumeTimeoutsEvent(suspendedWindow);
}
}
}
@ -2808,6 +2828,12 @@ nsXMLHttpRequest::Send(nsIVariant *aBody)
}
}
if (suspendedDoc) {
NS_DispatchToCurrentThread(
NS_NEW_RUNNABLE_METHOD(nsIDocument, suspendedDoc.get(),
UnsuppressEventHandling));
}
if (resumeTimeoutRunnable) {
NS_DispatchToCurrentThread(resumeTimeoutRunnable);
}
@ -3222,7 +3248,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 +3374,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 \

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

@ -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.get() : 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);
void clearMozAfterPaintEvents();
/**

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

@ -710,3 +710,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)
{